Repository: ariga/atlas
Branch: master
Commit: 9138a9fe419e
Files: 530
Total size: 4.0 MB
Directory structure:
gitextract_z_8o4h8f/
├── .github/
│ ├── ops/
│ │ └── mysql/
│ │ └── Dockerfile
│ └── workflows/
│ ├── cd-docker-push-cockroach_oss.yaml
│ ├── cd-docker-push-mysql_oss.yaml
│ ├── ci-dialect_oss.yaml
│ ├── ci-go_oss.yaml
│ ├── ci-revisions_oss.yaml
│ └── ci-sdk.yml
├── .golangci.yml
├── LICENSE
├── README.md
├── atlasexec/
│ ├── README.md
│ ├── atlas.go
│ ├── atlas_internal_test.go
│ ├── atlas_migrate.go
│ ├── atlas_migrate_example_test.go
│ ├── atlas_migrate_test.go
│ ├── atlas_models.go
│ ├── atlas_schema.go
│ ├── atlas_schema_test.go
│ ├── atlas_test.go
│ ├── copilot.go
│ ├── copilot_test.go
│ ├── internal/
│ │ └── e2e/
│ │ ├── sqlite_test.go
│ │ ├── testdata/
│ │ │ ├── multi-tenants/
│ │ │ │ ├── atlas.hcl
│ │ │ │ └── migrations/
│ │ │ │ ├── 20240112070806.sql
│ │ │ │ ├── 20240116003831.sql
│ │ │ │ └── atlas.sum
│ │ │ ├── schema-plan/
│ │ │ │ ├── schema-1.lt.hcl
│ │ │ │ └── schema-2.lt.hcl
│ │ │ └── versioned-basic/
│ │ │ ├── atlas.hcl
│ │ │ └── migrations/
│ │ │ ├── 20240112070806.sql
│ │ │ └── atlas.sum
│ │ └── util_e2e.go
│ ├── mock-atlas.sh
│ ├── testdata/
│ │ ├── broken/
│ │ │ ├── 20231029112426.sql
│ │ │ └── atlas.sum
│ │ └── migrations/
│ │ ├── 20230727105553_init.sql
│ │ ├── 20230727105615_t2.sql
│ │ ├── 20230926085734_destructive-change.sql
│ │ └── atlas.sum
│ ├── working_dir.go
│ └── working_dir_test.go
├── cmd/
│ └── atlas/
│ ├── go.mod
│ ├── go.sum
│ ├── internal/
│ │ ├── cloudapi/
│ │ │ ├── client.go
│ │ │ ├── client_oss.go
│ │ │ └── client_test.go
│ │ ├── cmdapi/
│ │ │ ├── cmdapi.go
│ │ │ ├── cmdapi_oss.go
│ │ │ ├── cmdapi_test.go
│ │ │ ├── migrate.go
│ │ │ ├── migrate_oss.go
│ │ │ ├── migrate_test.go
│ │ │ ├── project.go
│ │ │ ├── project_test.go
│ │ │ ├── schema.go
│ │ │ ├── schema_test.go
│ │ │ ├── testdata/
│ │ │ │ ├── baseline1/
│ │ │ │ │ ├── 1_baseline.sql
│ │ │ │ │ └── atlas.sum
│ │ │ │ ├── baseline2/
│ │ │ │ │ ├── 1_baseline.sql
│ │ │ │ │ ├── 20220318104614_initial.sql
│ │ │ │ │ ├── 20220318104615_second.sql
│ │ │ │ │ └── atlas.sum
│ │ │ │ ├── import/
│ │ │ │ │ ├── dbmate/
│ │ │ │ │ │ ├── 1_initial.sql
│ │ │ │ │ │ └── 2_second_migration.sql
│ │ │ │ │ ├── dbmate_gold/
│ │ │ │ │ │ ├── 1_initial.sql
│ │ │ │ │ │ └── 2_second_migration.sql
│ │ │ │ │ ├── flyway/
│ │ │ │ │ │ ├── B2__baseline.sql
│ │ │ │ │ │ ├── R__views.sql
│ │ │ │ │ │ ├── U1__initial.sql
│ │ │ │ │ │ ├── V1__initial.sql
│ │ │ │ │ │ ├── V2__second_migration.sql
│ │ │ │ │ │ └── V3__third_migration.sql
│ │ │ │ │ ├── flyway_gold/
│ │ │ │ │ │ ├── 2_baseline.sql
│ │ │ │ │ │ ├── 3R_views.sql
│ │ │ │ │ │ └── 3_third_migration.sql
│ │ │ │ │ ├── golang-migrate/
│ │ │ │ │ │ ├── 1_initial.down.sql
│ │ │ │ │ │ ├── 1_initial.up.sql
│ │ │ │ │ │ ├── 2_second_migration.down.sql
│ │ │ │ │ │ └── 2_second_migration.up.sql
│ │ │ │ │ ├── golang-migrate_gold/
│ │ │ │ │ │ ├── 1_initial.sql
│ │ │ │ │ │ └── 2_second_migration.sql
│ │ │ │ │ ├── goose/
│ │ │ │ │ │ ├── 1_initial.sql
│ │ │ │ │ │ └── 2_second_migration.sql
│ │ │ │ │ ├── goose_gold/
│ │ │ │ │ │ ├── 1_initial.sql
│ │ │ │ │ │ └── 2_second_migration.sql
│ │ │ │ │ ├── liquibase/
│ │ │ │ │ │ ├── 1_initial.sql
│ │ │ │ │ │ └── 2_second_migration.sql
│ │ │ │ │ └── liquibase_gold/
│ │ │ │ │ ├── 1_initial.sql
│ │ │ │ │ └── 2_second_migration.sql
│ │ │ │ ├── mysql/
│ │ │ │ │ ├── 20220318104614_initial.sql
│ │ │ │ │ ├── 20220420213403_second.sql
│ │ │ │ │ └── atlas.sum
│ │ │ │ ├── sqlite/
│ │ │ │ │ ├── 20220318104614_initial.sql
│ │ │ │ │ ├── 20220318104615_second.sql
│ │ │ │ │ └── atlas.sum
│ │ │ │ ├── sqlite2/
│ │ │ │ │ ├── 20220318104614_initial.sql
│ │ │ │ │ ├── 20220318104615_second.sql
│ │ │ │ │ └── atlas.sum
│ │ │ │ ├── sqlitetx/
│ │ │ │ │ ├── 20220925092817_initial.sql
│ │ │ │ │ ├── 20220925094021_second.sql
│ │ │ │ │ ├── 20220925094437_third.sql
│ │ │ │ │ └── atlas.sum
│ │ │ │ ├── sqlitetx2/
│ │ │ │ │ ├── 20220925092817_initial.sql
│ │ │ │ │ ├── 20220925094021_second.sql
│ │ │ │ │ ├── 20220925094437_third.sql
│ │ │ │ │ └── atlas.sum
│ │ │ │ ├── sqlitetx3/
│ │ │ │ │ ├── 20220925092817_initial.sql
│ │ │ │ │ ├── 20220925094021_second.sql
│ │ │ │ │ └── atlas.sum
│ │ │ │ ├── sqlitetx4/
│ │ │ │ │ ├── 20220925092817_initial.sql
│ │ │ │ │ ├── 20220925094021_second.sql
│ │ │ │ │ └── atlas.sum
│ │ │ │ └── templatedir/
│ │ │ │ ├── 1.sql
│ │ │ │ ├── 2.sql
│ │ │ │ ├── atlas.sum
│ │ │ │ └── shared/
│ │ │ │ └── users.sql
│ │ │ ├── vercheck/
│ │ │ │ ├── notification.tmpl
│ │ │ │ ├── req_oss.go
│ │ │ │ ├── vercheck.go
│ │ │ │ └── vercheck_test.go
│ │ │ ├── version_oss.go
│ │ │ └── version_oss_test.go
│ │ ├── cmdext/
│ │ │ ├── cmdext.go
│ │ │ ├── cmdext_oss.go
│ │ │ ├── cmdext_test.go
│ │ │ ├── reader.go
│ │ │ └── reader_test.go
│ │ ├── cmdlog/
│ │ │ ├── cmdlog.go
│ │ │ ├── cmdlog_oss.go
│ │ │ └── cmdlog_test.go
│ │ ├── cmdstate/
│ │ │ ├── cmdstate.go
│ │ │ └── cmdstate_test.go
│ │ ├── docker/
│ │ │ ├── docker.go
│ │ │ └── docker_test.go
│ │ ├── migrate/
│ │ │ ├── ent/
│ │ │ │ ├── client.go
│ │ │ │ ├── convert.go
│ │ │ │ ├── ent.go
│ │ │ │ ├── entc.go
│ │ │ │ ├── enttest/
│ │ │ │ │ └── enttest.go
│ │ │ │ ├── generate.go
│ │ │ │ ├── hook/
│ │ │ │ │ └── hook.go
│ │ │ │ ├── internal/
│ │ │ │ │ └── schemaconfig.go
│ │ │ │ ├── migrate/
│ │ │ │ │ ├── migrate.go
│ │ │ │ │ └── schema.go
│ │ │ │ ├── mutation.go
│ │ │ │ ├── predicate/
│ │ │ │ │ └── predicate.go
│ │ │ │ ├── revision/
│ │ │ │ │ ├── revision.go
│ │ │ │ │ └── where.go
│ │ │ │ ├── revision.go
│ │ │ │ ├── revision_create.go
│ │ │ │ ├── revision_delete.go
│ │ │ │ ├── revision_query.go
│ │ │ │ ├── revision_update.go
│ │ │ │ ├── runtime/
│ │ │ │ │ └── runtime.go
│ │ │ │ ├── runtime.go
│ │ │ │ ├── schema/
│ │ │ │ │ └── revision.go
│ │ │ │ ├── template/
│ │ │ │ │ └── convert.tmpl
│ │ │ │ └── tx.go
│ │ │ ├── migrate.go
│ │ │ ├── migrate_oss.go
│ │ │ ├── migrate_test.go
│ │ │ └── testdata/
│ │ │ ├── broken/
│ │ │ │ ├── 1.sql
│ │ │ │ ├── 2.sql
│ │ │ │ ├── 3.sql
│ │ │ │ └── atlas.sum
│ │ │ └── fixed/
│ │ │ ├── 1.sql
│ │ │ ├── 2.sql
│ │ │ ├── 3.sql
│ │ │ └── atlas.sum
│ │ ├── migratelint/
│ │ │ ├── lint.go
│ │ │ ├── lint_oss.go
│ │ │ └── lint_test.go
│ │ └── sqlparse/
│ │ ├── myparse/
│ │ │ └── myparse_oss.go
│ │ ├── parseutil/
│ │ │ └── parseutil.go
│ │ ├── pgparse/
│ │ │ └── pgparse_oss.go
│ │ ├── sqliteparse/
│ │ │ ├── Lexer.g4
│ │ │ ├── Parser.g4
│ │ │ ├── README.md
│ │ │ ├── lexer.go
│ │ │ ├── parser.go
│ │ │ ├── parser_base_listener.go
│ │ │ ├── parser_base_visitor.go
│ │ │ ├── parser_listener.go
│ │ │ ├── parser_visitor.go
│ │ │ └── sqliteparse_oss.go
│ │ └── sqlparse.go
│ ├── main.go
│ └── main_oss.go
├── go.mod
├── go.sum
├── internal/
│ ├── ci/
│ │ ├── ci_dialect.tmpl
│ │ ├── ci_go.tmpl
│ │ ├── ci_revisions.tmpl
│ │ ├── cockroach/
│ │ │ ├── Dockerfile.tmpl
│ │ │ └── main.go
│ │ ├── jobs_oss.go
│ │ └── main.go
│ └── integration/
│ ├── README.md
│ ├── cockroach_test.go
│ ├── docker-compose.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── hclsqlspec/
│ │ └── hclsqlspec_test.go
│ ├── integration_test.go
│ ├── mysql_test.go
│ ├── postgres_test.go
│ ├── script_test.go
│ ├── sqlite_test.go
│ ├── testdata/
│ │ ├── migrations/
│ │ │ ├── mysql/
│ │ │ │ ├── 1_initial.sql
│ │ │ │ └── atlas.sum
│ │ │ ├── mysqlock/
│ │ │ │ ├── 1.sql
│ │ │ │ ├── 2.sql
│ │ │ │ ├── 3.sql
│ │ │ │ └── atlas.sum
│ │ │ └── postgres/
│ │ │ ├── 1_initial.sql
│ │ │ └── atlas.sum
│ │ ├── mysql/
│ │ │ ├── autoincrement.txtar
│ │ │ ├── check-maria.txtar
│ │ │ ├── check.txtar
│ │ │ ├── cli-inspect-file.txtar
│ │ │ ├── cli-migrate-apply-datasrc.txtar
│ │ │ ├── cli-migrate-apply.txtar
│ │ │ ├── cli-migrate-diff-format.txtar
│ │ │ ├── cli-migrate-diff-mode-normalized.txtar
│ │ │ ├── cli-migrate-diff.txtar
│ │ │ ├── cli-project-schemas.txtar
│ │ │ ├── cli-project-url-escape.txtar
│ │ │ ├── cli-schema-apply-datasrc.txtar
│ │ │ ├── column-add-drop.txtar
│ │ │ ├── column-bit.txtar
│ │ │ ├── column-bool.txtar
│ │ │ ├── column-charset.txtar
│ │ │ ├── column-default-expr.txtar
│ │ │ ├── column-generated-inspect.txtar
│ │ │ ├── column-generated.txtar
│ │ │ ├── column-json.txtar
│ │ │ ├── column-time-precision-maria.txtar
│ │ │ ├── column-time-precision-mysql.txtar
│ │ │ ├── foreign-key-add.txtar
│ │ │ ├── foreign-key-modify-action.txtar
│ │ │ ├── foreign-key.txtar
│ │ │ ├── index-add-drop.txtar
│ │ │ ├── index-desc.txtar
│ │ │ ├── index-expr.txtar
│ │ │ ├── index-prefix.txtar
│ │ │ ├── index-type.txtar
│ │ │ ├── index-unique.txtar
│ │ │ ├── primary-key-parts.txtar
│ │ │ ├── primary-key.txtar
│ │ │ └── table-engine.txtar
│ │ ├── postgres/
│ │ │ ├── cli-inspect-file.txtar
│ │ │ ├── cli-inspect.txtar
│ │ │ ├── cli-migrate-apply-datasrc.txtar
│ │ │ ├── cli-migrate-apply.txtar
│ │ │ ├── cli-migrate-diff-unsupported.txtar
│ │ │ ├── cli-migrate-diff.txtar
│ │ │ ├── cli-migrate-status.txtar
│ │ │ ├── column-array.txtar
│ │ │ ├── column-bit.txtar
│ │ │ ├── column-comment.txtar
│ │ │ ├── column-default.txtar
│ │ │ ├── column-domain.txtar
│ │ │ ├── column-enum-array.txtar
│ │ │ ├── column-enum.txtar
│ │ │ ├── column-float.txtar
│ │ │ ├── column-generated-inspect.txtar
│ │ │ ├── column-identity.txtar
│ │ │ ├── column-interval.txtar
│ │ │ ├── column-numeric.txtar
│ │ │ ├── column-range.txtar
│ │ │ ├── column-serial.txtar
│ │ │ ├── column-textsearch.txtar
│ │ │ ├── column-time-precision.txtar
│ │ │ ├── foreign-key-action.txtar
│ │ │ ├── foreign-key.txtar
│ │ │ ├── index-desc.txtar
│ │ │ ├── index-expr.txtar
│ │ │ ├── index-include.txtar
│ │ │ ├── index-issue-557.txtar
│ │ │ ├── index-nulls-distinct.txtar
│ │ │ ├── index-operator-class.txtar
│ │ │ ├── index-partial.txtar
│ │ │ ├── index-type-brin.txtar
│ │ │ ├── index-type.txtar
│ │ │ ├── index-unique-constraint.txtar
│ │ │ ├── primary-key.txtar
│ │ │ ├── table-checks.txtar
│ │ │ └── table-partition.txtar
│ │ └── sqlite/
│ │ ├── autoincrement.txtar
│ │ ├── cli-apply-multifile.txtar
│ │ ├── cli-apply-project-multifile.txtar
│ │ ├── cli-apply-vars.txtar
│ │ ├── cli-inspect.txtar
│ │ ├── cli-migrate-apply.txtar
│ │ ├── cli-migrate-diff-datasrc-hcl-paths.txtar
│ │ ├── cli-migrate-diff-datasrc-hcl.txtar
│ │ ├── cli-migrate-diff-minimal-env.txtar
│ │ ├── cli-migrate-diff-multifile.txtar
│ │ ├── cli-migrate-diff-sql.txtar
│ │ ├── cli-migrate-diff.txtar
│ │ ├── cli-migrate-lint-add-notnull.txtar
│ │ ├── cli-migrate-lint-destructive.txtar
│ │ ├── cli-migrate-lint-ignore.txtar
│ │ ├── cli-migrate-lint-minimal-env.txtar
│ │ ├── cli-migrate-lint-project.txtar
│ │ ├── cli-migrate-project-multifile.txtar
│ │ ├── cli-migrate-project.txtar
│ │ ├── cli-migrate-set.txtar
│ │ ├── cli-project-vars.txtar
│ │ ├── cli-schema-project-file.txtar
│ │ ├── column-default.txtar
│ │ ├── column-generated.txtar
│ │ ├── column-user-defined.txtar
│ │ ├── index-desc.txtar
│ │ ├── index-expr.txtar
│ │ ├── index-partial.txtar
│ │ └── table-options.txtar
│ ├── tidb_test.go
│ └── tools.go
├── schemahcl/
│ ├── context.go
│ ├── context_test.go
│ ├── extension.go
│ ├── extension_test.go
│ ├── schemahcl.go
│ ├── schemahcl_test.go
│ ├── spec.go
│ ├── spec_test.go
│ ├── stdlib.go
│ ├── stdlib_test.go
│ ├── testdata/
│ │ ├── a.hcl
│ │ ├── b.hcl
│ │ ├── nested/
│ │ │ └── c.hcl
│ │ └── variables.hcl
│ ├── types.go
│ └── types_test.go
├── sdk/
│ ├── recordriver/
│ │ ├── driver.go
│ │ └── driver_test.go
│ └── tmplrun/
│ ├── testdata/
│ │ ├── app.tmpl
│ │ └── foo.go
│ ├── tmplrun.go
│ └── tmplrun_test.go
└── sql/
├── internal/
│ ├── spectest/
│ │ └── spectest.go
│ ├── specutil/
│ │ ├── convert.go
│ │ ├── convert_test.go
│ │ └── spec.go
│ ├── sqltest/
│ │ └── sqltest.go
│ └── sqlx/
│ ├── dev.go
│ ├── dev_test.go
│ ├── diff.go
│ ├── plan.go
│ ├── plan_test.go
│ ├── sqlx.go
│ ├── sqlx_oss.go
│ └── sqlx_test.go
├── migrate/
│ ├── dir.go
│ ├── dir_test.go
│ ├── lex.go
│ ├── lex_test.go
│ ├── migrate.go
│ ├── migrate_oss.go
│ ├── migrate_test.go
│ └── testdata/
│ ├── golang-migrate/
│ │ └── 1_base.up.sql
│ ├── lex/
│ │ ├── 1.sql
│ │ ├── 1.sql.golden
│ │ ├── 10_delimiter_comment.sql
│ │ ├── 10_delimiter_comment.sql.golden
│ │ ├── 11_delimiter_mysql_command.sql
│ │ ├── 11_delimiter_mysql_command.sql.golden
│ │ ├── 12_delimiter_mysql_command.sql
│ │ ├── 12_delimiter_mysql_command.sql.golden
│ │ ├── 13_delimiter_mysql_command.sql
│ │ ├── 13_delimiter_mysql_command.sql.golden
│ │ ├── 14_delimiter_mysql_command.sql
│ │ ├── 14_delimiter_mysql_command.sql.golden
│ │ ├── 15_dollar_quote.sql
│ │ ├── 15_dollar_quote.sql.golden
│ │ ├── 16_begin_atomic.sql
│ │ ├── 16_begin_atomic.sql.golden
│ │ ├── 17_paren.sql
│ │ ├── 17_paren.sql.golden
│ │ ├── 18_pg_expr.sql
│ │ ├── 18_pg_expr.sql.golden
│ │ ├── 19_ms_gocmd.sql
│ │ ├── 19_ms_gocmd.sql.golden
│ │ ├── 20_ms_go-delim.sql
│ │ ├── 20_ms_go-delim.sql.golden
│ │ ├── 2_mysql.sql
│ │ ├── 2_mysql.sql.golden
│ │ ├── 3_delimiter.sql
│ │ ├── 3_delimiter.sql.golden
│ │ ├── 4_delimiter.sql
│ │ ├── 4_delimiter.sql.golden
│ │ ├── 5_delimiter.sql
│ │ ├── 5_delimiter.sql.golden
│ │ ├── 6_skip_comment.sql
│ │ ├── 6_skip_comment.sql.golden
│ │ ├── 7_delimiter_2n.sql
│ │ ├── 7_delimiter_2n.sql.golden
│ │ ├── 8_delimiter_3n.sql
│ │ ├── 8_delimiter_3n.sql.golden
│ │ ├── 9_delimiter_3n.sql
│ │ └── 9_delimiter_3n.sql.golden
│ ├── lexbegintry/
│ │ ├── 1.sql
│ │ └── 1.sql.golden
│ ├── lexescaped/
│ │ ├── 1.my.sql
│ │ ├── 1.my.sql.golden
│ │ ├── 2.pg.sql
│ │ └── 2.pg.sql.golden
│ ├── lexgroup/
│ │ ├── 1_trigger.sql
│ │ ├── 1_trigger.sql.golden
│ │ ├── 2_function.sql
│ │ ├── 2_function.sql.golden
│ │ ├── 3_delimiter.sql
│ │ └── 3_delimiter.sql.golden
│ ├── migrate/
│ │ ├── 1_initial.down.sql
│ │ ├── 1_initial.up.sql
│ │ ├── atlas.sum
│ │ └── sub/
│ │ ├── 1.a_sub.up.sql
│ │ ├── 2.10.x-20_description.sql
│ │ ├── 3_partly.sql
│ │ └── atlas.sum
│ ├── partial-checkpoint/
│ │ ├── 1_first.sql
│ │ ├── 2_second.sql
│ │ ├── 3_checkpoint.sql
│ │ ├── 4_fourth.sql
│ │ ├── 5_checkpoint.sql
│ │ ├── 6_sixth.sql
│ │ └── atlas.sum
│ └── sqlserver/
│ ├── 1_return_table.sql
│ ├── 1_return_table.sql.golden
│ ├── 2_function.sql
│ └── 2_function.sql.golden
├── mysql/
│ ├── convert.go
│ ├── diff_oss.go
│ ├── diff_oss_test.go
│ ├── driver_oss.go
│ ├── driver_oss_test.go
│ ├── inspect_oss.go
│ ├── inspect_oss_test.go
│ ├── internal/
│ │ └── mysqlversion/
│ │ ├── is/
│ │ │ ├── .README.md
│ │ │ ├── charset2collate
│ │ │ ├── charset2collate.maria
│ │ │ ├── collate2charset
│ │ │ └── collate2charset.maria
│ │ ├── mysqlversion.go
│ │ └── mysqlversion_test.go
│ ├── migrate_oss.go
│ ├── migrate_oss_test.go
│ ├── mysqlcheck/
│ │ ├── mysqlcheck.go
│ │ ├── mysqlcheck_oss.go
│ │ └── mysqlcheck_test.go
│ ├── sqlspec_oss.go
│ ├── sqlspec_oss_test.go
│ └── tidb.go
├── postgres/
│ ├── convert.go
│ ├── crdb_oss.go
│ ├── diff_oss.go
│ ├── diff_oss_test.go
│ ├── driver_oss.go
│ ├── driver_oss_test.go
│ ├── inspect_oss.go
│ ├── inspect_oss_test.go
│ ├── internal/
│ │ └── postgresop/
│ │ └── postgresop.go
│ ├── migrate_oss.go
│ ├── migrate_oss_test.go
│ ├── postgrescheck/
│ │ ├── postgrescheck.go
│ │ ├── postgrescheck_oss.go
│ │ └── postgrescheck_test.go
│ ├── sqlspec_oss.go
│ └── sqlspec_oss_test.go
├── schema/
│ ├── changekind_string.go
│ ├── dsl.go
│ ├── dsl_test.go
│ ├── exclude_oss.go
│ ├── inspect.go
│ ├── migrate.go
│ ├── migrate_test.go
│ └── schema.go
├── sqlcheck/
│ ├── condrop/
│ │ ├── condrop.go
│ │ └── condrop_test.go
│ ├── datadepend/
│ │ ├── datadepend.go
│ │ └── datadepend_test.go
│ ├── destructive/
│ │ ├── destructive.go
│ │ ├── destructive_oss.go
│ │ └── destructive_test.go
│ ├── incompatible/
│ │ ├── incompatible.go
│ │ └── incompatible_test.go
│ └── sqlcheck.go
├── sqlclient/
│ ├── client.go
│ └── client_test.go
├── sqlite/
│ ├── convert.go
│ ├── diff.go
│ ├── diff_test.go
│ ├── driver.go
│ ├── driver_oss.go
│ ├── driver_test.go
│ ├── inspect.go
│ ├── inspect_test.go
│ ├── migrate.go
│ ├── migrate_test.go
│ ├── sqlitecheck/
│ │ ├── sqlitecheck.go
│ │ ├── sqlitecheck_oss.go
│ │ └── sqlitecheck_test.go
│ ├── sqlspec.go
│ └── sqlspec_test.go
├── sqlspec/
│ ├── sqlspec.go
│ └── sqlspec_test.go
└── sqltool/
├── doc.go
├── hidden.go
├── hidden_windows.go
├── testdata/
│ ├── dbmate/
│ │ ├── 1_initial.sql
│ │ └── 2_second_migration.sql
│ ├── flyway/
│ │ ├── B2__baseline.sql
│ │ ├── R__views.sql
│ │ ├── U1__initial.sql
│ │ ├── V1__initial.sql
│ │ ├── V2__second_migration.sql
│ │ ├── V3__third_migration.sql
│ │ └── v3/
│ │ └── V3_1__fourth_migration.sql
│ ├── golang-migrate/
│ │ ├── 1_initial.down.sql
│ │ ├── 1_initial.up.sql
│ │ ├── 2_second_migration.down.sql
│ │ └── 2_second_migration.up.sql
│ ├── goose/
│ │ ├── 1_initial.sql
│ │ └── 2_second_migration.sql
│ └── liquibase/
│ ├── 1_initial.sql
│ └── 2_second_migration.sql
├── tool.go
└── tool_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ops/mysql/Dockerfile
================================================
ARG DIALECT=mysql:8.0
FROM $DIALECT as builder
ARG SERVER=mysqld
ENV MYSQL_ROOT_PASSWORD=pass
# Remove the last line of the entry point script, leaving the initialization code but omitting actually starting the db.
RUN sed -i 's/exec "$@"/echo "not running $@"/' /usr/local/bin/docker-entrypoint.sh
RUN /usr/local/bin/docker-entrypoint.sh ${SERVER}
FROM $DIALECT
COPY --from=builder /var/lib/mysql /var/lib/mysql
================================================
FILE: .github/workflows/cd-docker-push-cockroach_oss.yaml
================================================
name: CD - Build Docker - Cockroach - Community Edition
on:
pull_request:
push:
branches:
- master
env:
CRDB_VERSIONS: v21.2.11 v22.1.0
jobs:
build-services:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
- name: "build cockroach image"
run: |
VER="${{ env.CRDB_VERSIONS }}"
for i in $VER
do
:
if ! docker manifest inspect ghcr.io/ariga/cockroachdb-single-node:$i; then
go run internal/ci/cockroach/main.go $i > internal/ci/cockroach/Dockerfile
docker build -t ghcr.io/ariga/cockroachdb-single-node:$i internal/ci/cockroach/
docker push ghcr.io/ariga/cockroachdb-single-node:$i
else
echo image already exists
fi
done
================================================
FILE: .github/workflows/cd-docker-push-mysql_oss.yaml
================================================
name: CD - Build Docker - MySQL Quick Boot - Community Edition
on:
push:
paths:
- .github/ops/mysql/**
- .github/workflows/cd-docker-push-mysql_oss.yaml
branches:
- master
schedule:
# Runs at 00:00 on Sunday
- cron: '0 0 * * 0'
workflow_dispatch:
jobs:
push-docker:
strategy:
fail-fast: false
matrix:
include:
- dialect: mysql:latest
- dialect: mysql:5.6
platforms: linux/amd64
- dialect: mysql:5.6.35
platforms: linux/amd64
- dialect: mysql:5.7
platforms: linux/amd64
- dialect: mysql:5.7.26
platforms: linux/amd64
- dialect: mysql:8
- dialect: mysql:8.0.40
- dialect: mysql:8.4
- dialect: mysql:8.4.0
- dialect: mysql:8.3
- dialect: mysql:8.3.0
- dialect: mariadb:latest
build-args: SERVER=mariadbd
- dialect: mariadb:10.2
- dialect: mariadb:10.2.32
- dialect: mariadb:10.3
- dialect: mariadb:10.3.13
platforms: linux/amd64
- dialect: mariadb:10.7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build & Push ${{ matrix.dialect }} Docker Image
uses: docker/build-push-action@v2
with:
context: .
file: ./.github/ops/mysql/Dockerfile
push: true
tags: arigaio/${{ matrix.dialect }}
platforms: ${{ matrix.platforms || 'linux/amd64,linux/arm64' }}
build-args: |
DIALECT=${{ matrix.dialect }}
${{ matrix.build-args }}
================================================
FILE: .github/workflows/ci-dialect_oss.yaml
================================================
# # # # # # # # # # # # # # # #
# CODE GENERATED - DO NOT EDIT
# # # # # # # # # # # # # # # #
name: CI - Dialect Tests - Community Edition
on:
workflow_call:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}-dialect
cancel-in-progress: true
env:
ATLAS_NO_UPGRADE_SUGGESTIONS: 1
jobs:
integration-mysql56:
runs-on: ubuntu-latest
services:
mysql56:
image: mysql:5.6.35
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 3306:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for mysql56
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="mysql56" -timeout 15m ./...
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
integration-mysql57:
runs-on: ubuntu-latest
services:
mysql57:
image: mysql:5.7.26
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 3307:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for mysql57
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="mysql57" -timeout 15m ./...
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
integration-mysql8:
runs-on: ubuntu-latest
services:
mysql8:
image: mysql:8
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 3308:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for mysql8
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="mysql8" -timeout 15m ./...
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
integration-maria107:
runs-on: ubuntu-latest
services:
maria107:
image: mariadb:10.7
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 4306:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for maria107
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="maria107" -timeout 15m ./...
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
integration-maria102:
runs-on: ubuntu-latest
services:
maria102:
image: mariadb:10.2.32
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 4307:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for maria102
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="maria102" -timeout 15m ./...
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
integration-maria103:
runs-on: ubuntu-latest
services:
maria103:
image: mariadb:10.3.13
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 4308:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for maria103
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="maria103" -timeout 15m ./...
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
integration-postgres-ext-postgis:
runs-on: ubuntu-latest
services:
postgres-ext-postgis:
image: postgis/postgis:latest
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5429:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for postgres-ext-postgis
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres-ext-postgis" -timeout 15m ./...
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
integration-postgres10:
runs-on: ubuntu-latest
services:
postgres10:
image: postgres:10
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5430:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for postgres10
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres10" -timeout 15m ./...
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
integration-postgres11:
runs-on: ubuntu-latest
services:
postgres11:
image: postgres:11
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5431:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for postgres11
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres11" -timeout 15m ./...
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
integration-postgres12:
runs-on: ubuntu-latest
services:
postgres12:
image: postgres:12.3
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for postgres12
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres12" -timeout 15m ./...
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
integration-postgres13:
runs-on: ubuntu-latest
services:
postgres13:
image: postgres:13.1
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5433:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for postgres13
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres13" -timeout 15m ./...
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
integration-postgres14:
runs-on: ubuntu-latest
services:
postgres14:
image: postgres:14
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5434:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for postgres14
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres14" -timeout 15m ./...
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
integration-postgres15:
runs-on: ubuntu-latest
services:
postgres15:
image: postgres:15
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5435:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for postgres15
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres15" -timeout 15m ./...
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
integration-sqlite:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for sqlite
working-directory: internal/integration
run: go test -race -count=2 -v -run="SQLite.*" -version="sqlite" -timeout 15m ./...
integration-tidb5:
runs-on: ubuntu-latest
services:
tidb5:
image: pingcap/tidb:v5.4.0
ports:
- 4309:4000
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for tidb5
working-directory: internal/integration
run: go test -race -count=2 -v -run="TiDB" -version="tidb5" -timeout 15m ./...
integration-tidb6:
runs-on: ubuntu-latest
services:
tidb6:
image: pingcap/tidb:v6.0.0
ports:
- 4310:4000
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for tidb6
working-directory: internal/integration
run: go test -race -count=2 -v -run="TiDB" -version="tidb6" -timeout 15m ./...
integration-cockroach:
runs-on: ubuntu-latest
services:
cockroach:
image: ghcr.io/ariga/cockroachdb-single-node:v21.2.11
ports:
- 26257:26257
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for cockroach
working-directory: internal/integration
run: go test -race -count=2 -v -run="Cockroach" -version="cockroach" -timeout 15m ./...
================================================
FILE: .github/workflows/ci-go_oss.yaml
================================================
# # # # # # # # # # # # # # # #
# CODE GENERATED - DO NOT EDIT
# # # # # # # # # # # # # # # #
name: CI - General - Community Edition
on:
pull_request:
paths-ignore:
- 'doc/**'
- 'ops/**'
push:
branches:
- master
paths-ignore:
- 'doc/**'
- 'ops/**'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
ATLAS_NO_UPGRADE_SUGGESTIONS: 1
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run linters
uses: golangci/golangci-lint-action@v6
with:
args: --verbose
generate-cmp:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Install stringer
run: go install golang.org/x/tools/cmd/stringer@latest
- name: run "go generate ./..."
run: go generate ./...
- name: go generate cmd/atlas
working-directory: cmd/atlas
run: go generate ./...
- name: Verify generated files are checked-in properly
run: |
status=$(git status --porcelain | grep -v "go.\(sum\|mod\)" | cat)
if [ -n "$status" ]; then
echo "you need to run 'go generate ./...' and commit the changes"
echo "$status"
exit 1
fi
unit:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ "1.22" ]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Run sql tests
run: go test -race ./...
working-directory: sql
- name: Run schemahcl tests
run: go test -race ./...
working-directory: schemahcl
cli:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run cli tests
run: go test -race ./...
working-directory: cmd/atlas
integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Run integration tests for HCL
working-directory: internal/integration/hclsqlspec
run: go test -race -count=2 -v ./...
dialect-integration:
needs: [lint, generate-cmp, unit, cli, integration]
uses: ./.github/workflows/ci-dialect_oss.yaml
secrets: inherit
================================================
FILE: .github/workflows/ci-revisions_oss.yaml
================================================
# # # # # # # # # # # # # # # #
# CODE GENERATED - DO NOT EDIT
# # # # # # # # # # # # # # # #
name: CI - Revisions - Community Edition
on:
pull_request:
paths:
- 'cmd/atlas/internal/migrate/ent/**'
push:
branches:
- master
paths:
- 'cmd/atlas/internal/migrate/ent/**'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
revisions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
- name: Checkout origin/master
run: git checkout origin/master
- name: Create revisions from master
run: go run . migrate apply --dir file://internal/cmdapi/testdata/sqlite --url sqlite://db?_fk=1
working-directory: cmd/atlas
- name: Checkout previous HEAD
run: git checkout -
- name: Migrate revisions table to HEAD
run: go run . migrate apply --dir file://internal/cmdapi/testdata/sqlite --url sqlite://db?_fk=1
working-directory: cmd/atlas
================================================
FILE: .github/workflows/ci-sdk.yml
================================================
name: Go SDK CI
on:
push:
branches:
- master
pull_request:
jobs:
golangci-lint:
runs-on: ubuntu-latest
strategy:
matrix:
module: ["atlasexec", "sdk"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: ./go.mod
- name: Run Go linters
uses: golangci/golangci-lint-action@v6
with:
working-directory: ${{ matrix.module }}
args: --verbose --timeout 15m
unit-tests:
runs-on: ubuntu-latest
strategy:
matrix:
module: ["atlasexec", "sdk"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: ./go.mod
- uses: ariga/setup-atlas@v0
with:
cloud-token: ${{ secrets.ATLAS_TOKEN }}
env:
ATLAS_DEBUG: "true"
- name: Run tests
run: go test -race ./...
working-directory: ${{ matrix.module }}
e2e-tests:
runs-on: ubuntu-latest
services:
postgres:
image: postgres
env:
POSTGRES_PASSWORD: pass
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: ./go.mod
- uses: ariga/setup-atlas@v0
with:
cloud-token: ${{ secrets.ATLAS_TOKEN }}
env:
ATLAS_DEBUG: "true"
- name: Run e2e tests
run: go test ./internal/e2e
working-directory: atlasexec
env:
ATLASEXEC_E2ETEST: "1"
ATLASEXEC_E2ETEST_ATLAS_PATH: atlas
ATLASEXEC_E2ETEST_POSTGRES_URL: "postgres://postgres:pass@localhost:5432/postgres?search_path=public&sslmode=disable"
================================================
FILE: .golangci.yml
================================================
run:
timeout: 3m
issues:
include:
- EXC0012
exclude:
- G601
- G404
- redefines-builtin-id
exclude-rules:
- path: _test\.go
linters:
- gosec
- path: sql/migrate/dir.go
linters:
- gosec
- path: sql/mysql/inspect_oss.go
linters:
- gosec
- path: sql/migrate/lex.go
linters:
- revive
- path: sql/internal/sqlx/diff.go
linters:
- revive
linters-settings:
goheader:
template: |-
Copyright 2021-present The Atlas Authors. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
linters:
disable-all: true
enable:
- gosec
- revive
- goheader
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
================================================
FILE: README.md
================================================
# Atlas - Manage Your Database Schema as Code
[](https://twitter.com/atlasgo_io)
[](https://discord.com/invite/zZ6sWVg6NT)
Atlas is a language-agnostic tool for managing and migrating database schemas using modern DevOps principles.
It offers two workflows:
- **Declarative**: Similar to Terraform, Atlas compares the current state of the database to the desired state, as
defined in an [HCL], [SQL], or [ORM] schema. Based on this comparison, it generates and executes a migration plan to
transition the database to its desired state.
- **Versioned**: Unlike other tools, Atlas automatically plans schema migrations for you. Users can describe their desired
database schema in [HCL], [SQL], or their chosen [ORM], and by utilizing Atlas, they can plan, lint, and apply the
necessary migrations to the database.
## Supported Databases
[PostgreSQL](https://atlasgo.io/guides/postgres) ·
[MySQL](https://atlasgo.io/guides/mysql) ·
[MariaDB](https://atlasgo.io/guides/mysql) ·
[SQL Server](https://atlasgo.io/guides/mssql) ·
[SQLite](https://atlasgo.io/guides/sqlite) ·
[ClickHouse](https://atlasgo.io/guides/clickhouse) ·
[Redshift](https://atlasgo.io/guides/redshift) ·
[Oracle](https://atlasgo.io/guides/oracle) ·
[Snowflake](https://atlasgo.io/guides/snowflake) ·
[CockroachDB](https://atlasgo.io/guides/cockroachdb) ·
[TiDB](https://atlasgo.io/guides/mysql) ·
[Databricks](https://atlasgo.io/guides/databricks) ·
[Spanner](https://atlasgo.io/guides/spanner) ·
[Aurora DSQL](https://atlasgo.io/guides/dsql) ·
[Azure Fabric](https://atlasgo.io/guides/azure-fabric)
## Installation
**macOS + Linux:**
```bash
curl -sSf https://atlasgo.sh | sh
```
**Homebrew:**
```bash
brew install ariga/tap/atlas
```
**Docker:**
```bash
docker pull arigaio/atlas
```
**NPM:**
```bash
npx @ariga/atlas
```
See [installation docs](https://atlasgo.io/getting-started#installation) for all platforms.
## Key Features
- **[Declarative schema migrations](https://atlasgo.io/declarative/apply)**: The `atlas schema` command offers various options for [inspecting](https://atlasgo.io/inspect), diffing, comparing, [planning](https://atlasgo.io/declarative/plan) and applying migrations using standard Terraform-like workflows.
- **[Versioned migrations](https://atlasgo.io/versioned/intro)**: The `atlas migrate` command provides a state-of-the-art experience for [planning](https://atlasgo.io/versioned/diff), [linting](https://atlasgo.io/lint/analyzers), and [applying](https://atlasgo.io/versioned/apply) migrations.
- **[Schema as Code](https://atlasgo.io/atlas-schema)**: Define your desired database schema using [SQL], [HCL], or your chosen [ORM]. Atlas supports [16 ORM loaders](https://atlasgo.io/orms) across 6 languages.
- **[Security-as-Code](https://atlasgo.io/guides/postgres/security-declarative)**: Manage roles, permissions, and [row-level security](https://atlasgo.io/guides/postgres/row-level-security) policies as version-controlled code.
- **[Data management](https://atlasgo.io/atlas-schema/sql)**: Manage seed and lookup data declaratively alongside your schema.
- **[Cloud-native CI/CD](https://atlasgo.io/integrations)**: [Kubernetes operator](https://atlasgo.io/integrations/kubernetes), [Terraform provider](https://atlasgo.io/integrations/terraform), [GitHub Actions](https://atlasgo.io/integrations/github-actions), [GitLab CI](https://atlasgo.io/integrations/gitlab), [ArgoCD](https://atlasgo.io/integrations/kubernetes/argocd), and more.
- **[Testing framework](https://atlasgo.io/testing/schema)**: Unit test schema logic (functions, views, triggers, procedures) and [migration behavior](https://atlasgo.io/testing/migrate).
- **[50+ safety analyzers](https://atlasgo.io/lint/analyzers)**: Database-aware migration linting that detects destructive changes, data-dependent modifications, table locks, backward-incompatible changes, and more.
- **[Multi-tenancy](https://atlasgo.io/guides/multi-tenancy)**: Built-in support for multi-tenant database migrations.
- **[Drift detection](https://atlasgo.io/monitoring)**: Monitoring as Code with automatic schema drift detection and remediation.
- **[Cloud integration](https://atlasgo.io/guides/deploying/secrets)**: IAM-based authentication for [AWS RDS](https://atlasgo.io/guides/deploying/secrets#aws-rds-iam-authentication) and [GCP Cloud SQL](https://atlasgo.io/guides/deploying/secrets#gcp-cloudsql-iam-authentication), secrets management via [AWS Secrets Manager](https://atlasgo.io/guides/deploying/secrets#aws-secrets-manager), [GCP Secret Manager](https://atlasgo.io/guides/deploying/secrets#gcp-secret-manager), [HashiCorp Vault](https://atlasgo.io/guides/deploying/secrets#hashicorp-vault), and more.
## Getting Started
Get started with Atlas by following the [Getting Started](https://atlasgo.io/getting-started/) docs.
Inspect an existing database schema:
```shell
atlas schema inspect -u "postgres://localhost:5432/mydb"
```
Apply your desired schema to the database:
```shell
atlas schema apply \
--url "postgres://localhost:5432/mydb" \
--to file://schema.hcl \
--dev-url "docker://postgres/16/dev"
```
📖 [Getting Started docs](https://atlasgo.io/getting-started/)
## Migration Linting
Atlas ships with 50+ built-in [analyzers](https://atlasgo.io/lint/analyzers) that review your migration files
and catch issues before they reach production. Analyzers detect [destructive changes](https://atlasgo.io/lint/analyzers#destructive-changes)
like dropped tables or columns, [data-dependent modifications](https://atlasgo.io/lint/analyzers#data-dependent-changes)
such as adding non-nullable columns without defaults, and database-specific risks like table locks
and table rewrites that can cause downtime on busy tables. You can also define
your own [custom policy rules](https://atlasgo.io/lint/rules).
```bash
atlas migrate lint --dev-url "docker://postgres/16/dev"
```
## Schema Testing
[Test](https://atlasgo.io/testing/schema) database logic (functions, views, triggers, procedures) and
[data migrations](https://atlasgo.io/testing/migrate) with `.test.hcl` files:
```hcl
test "schema" "postal" {
# Valid postal codes pass
exec {
sql = "SELECT '12345'::us_postal_code"
}
# Invalid postal codes fail
catch {
sql = "SELECT 'hello'::us_postal_code"
}
}
test "schema" "seed" {
for_each = [
{input: "hello", expected: "HELLO"},
{input: "world", expected: "WORLD"},
]
exec {
sql = "SELECT upper('${each.value.input}')"
output = each.value.expected
}
}
```
```bash
atlas schema test --dev-url "docker://postgres/16/dev"
```
📖 [Testing docs](https://atlasgo.io/testing/schema)
## Security-as-Code
Manage database [roles, permissions](https://atlasgo.io/guides/postgres/security-declarative), and
[row-level security](https://atlasgo.io/guides/postgres/row-level-security) as version-controlled code:
```hcl
role "app_readonly" {
comment = "Read-only access for reporting"
}
role "app_writer" {
comment = "Read-write access for the application"
member_of = [role.app_readonly]
}
user "api_user" {
password = var.api_password
conn_limit = 20
comment = "Application API service account"
member_of = [role.app_writer]
}
permission {
for_each = [table.orders, table.products, table.users]
for = each.value
to = role.app_readonly
privileges = [SELECT]
}
policy "tenant_isolation" {
on = table.orders
for = ALL
to = ["app_writer"]
using = "(tenant_id = current_setting('app.current_tenant')::integer)"
check = "(tenant_id = current_setting('app.current_tenant')::integer)"
}
```
📖 [Security-as-Code docs](https://atlasgo.io/guides/postgres/security-declarative)
## Data Management
Manage seed and lookup data declaratively alongside your schema:
```sql
CREATE TABLE countries (
id INT PRIMARY KEY,
code VARCHAR(2) NOT NULL,
name VARCHAR(100) NOT NULL
);
INSERT INTO countries (id, code, name) VALUES
(1, 'US', 'United States'),
(2, 'IL', 'Israel'),
(3, 'DE', 'Germany');
```
📖 [Data management docs](https://atlasgo.io/atlas-schema/sql)
## ORM Support
Define your schema in any of the 16 supported ORMs. Atlas reads your models and generates migrations:
| Language | ORMs |
|----------|------|
| Go | [GORM](https://atlasgo.io/guides/orms/gorm), [Ent](https://atlasgo.io/guides/orms/ent), [Bun](https://atlasgo.io/guides/orms/bun), [Beego](https://atlasgo.io/guides/orms/beego), [sqlc](https://atlasgo.io/guides/frameworks/sqlc-versioned) |
| TypeScript | [Prisma](https://atlasgo.io/guides/orms/prisma), [Drizzle](https://atlasgo.io/guides/orms/drizzle), [TypeORM](https://atlasgo.io/guides/orms/typeorm), [Sequelize](https://atlasgo.io/guides/orms/sequelize) |
| Python | [Django](https://atlasgo.io/guides/orms/django), [SQLAlchemy](https://atlasgo.io/guides/orms/sqlalchemy) |
| Java | [Hibernate](https://atlasgo.io/guides/orms/hibernate) |
| .NET | [EF Core](https://atlasgo.io/guides/orms/efcore) |
| PHP | [Doctrine](https://atlasgo.io/guides/orms/doctrine) |
📖 [ORM integration docs](https://atlasgo.io/orms)
## Integrations
Lint, test, and apply migrations automatically in your CI/CD pipeline or infrastructure-as-code workflow:
| Integration | Docs |
|-------------|------|
| GitHub Actions | [Versioned guide](https://atlasgo.io/guides/ci-platforms/github-versioned) · [Declarative guide](https://atlasgo.io/guides/ci-platforms/github-declarative) |
| GitLab CI | [Versioned guide](https://atlasgo.io/guides/ci-platforms/gitlab-versioned) · [Declarative guide](https://atlasgo.io/guides/ci-platforms/gitlab-declarative) |
| CircleCI | [Versioned guide](https://atlasgo.io/guides/ci-platforms/circleci-versioned) · [Declarative guide](https://atlasgo.io/guides/ci-platforms/circleci-declarative) |
| Bitbucket Pipes | [Versioned guide](https://atlasgo.io/guides/ci-platforms/bitbucket-versioned) · [Declarative guide](https://atlasgo.io/guides/ci-platforms/bitbucket-declarative) |
| Azure DevOps | [GitHub repos](https://atlasgo.io/guides/ci-platforms/azure-devops-github) · [Azure repos](https://atlasgo.io/guides/ci-platforms/azure-devops-repos) |
| Terraform Provider | [atlasgo.io/integrations/terraform-provider](https://atlasgo.io/integrations/terraform-provider) |
| Kubernetes Operator | [atlasgo.io/integrations/kubernetes](https://atlasgo.io/integrations/kubernetes) |
| ArgoCD | [atlasgo.io/guides/deploying/k8s-argo](https://atlasgo.io/guides/deploying/k8s-argo) |
| Flux | [atlasgo.io/guides/deploying/k8s-flux](https://atlasgo.io/guides/deploying/k8s-flux) |
| Crossplane | [atlasgo.io/guides/deploying/crossplane](https://atlasgo.io/guides/deploying/crossplane) |
| Go SDK | [pkg.go.dev/ariga.io/atlas-go-sdk/atlasexec](https://pkg.go.dev/ariga.io/atlas-go-sdk/atlasexec) |
### AI Agent Integration
Atlas provides [Agent Skills](https://atlasgo.io/guides/ai-tools/agent-skills), an open standard for packaging
migration expertise for AI coding assistants:
[Claude Code](https://atlasgo.io/guides/ai-tools/claude-code-instructions),
[GitHub Copilot](https://atlasgo.io/guides/ai-tools/github-copilot-instructions),
[Cursor](https://atlasgo.io/guides/ai-tools/cursor-rules),
[OpenAI Codex](https://atlasgo.io/guides/ai-tools/codex-instructions). Learn more at [AI tools docs](https://atlasgo.io/guides/ai-tools).
## CLI Usage
### `schema inspect`
_**Easily inspect your database schema by providing a database URL and convert it to HCL, JSON, SQL, ERD, or other formats.**_
Inspect a specific MySQL schema and get its representation in Atlas DDL syntax:
```shell
atlas schema inspect -u "mysql://root:pass@localhost:3306/example" > schema.hcl
```
Result
```hcl
table "users" {
schema = schema.example
column "id" {
null = false
type = int
}
...
}
```
Inspect the entire MySQL database and get its JSON representation:
```shell
atlas schema inspect \
--url "mysql://root:pass@localhost:3306/" \
--format '{{ json . }}' | jq
```
Result
```json
{
"schemas": [
{
"name": "example",
"tables": [
{
"name": "users",
"columns": [
...
]
}
]
}
]
}
```
Inspect a specific PostgreSQL schema and get its ERD representation in Mermaid syntax:
```shell
atlas schema inspect \
--url "postgres://root:pass@:5432/test?search_path=public&sslmode=disable" \
--format '{{ mermaid . }}'
```
```mermaid
erDiagram
users {
int id PK
varchar name
}
blog_posts {
int id PK
varchar title
text body
int author_id FK
}
blog_posts }o--o| users : author_fk
```
Use the [split format](https://atlasgo.io/inspect/database-to-code) for one-file-per-object output:
```bash
atlas schema inspect -u '' --format '{{ sql . | split | write }}'
```
```
├── schemas
│ └── public
│ ├── public.sql
│ ├── tables
│ │ ├── profiles.sql
│ │ └── users.sql
│ ├── functions
│ └── types
└── main.sql
```
📖 [Schema inspection docs](https://atlasgo.io/inspect)
### `schema diff`
_**Compare two schema states and get a migration plan to transform one into the other. A state can be specified using a
database URL, HCL, SQL, or ORM schema, or a migration directory.**_
```shell
atlas schema diff \
--from "postgres://postgres:pass@:5432/test?search_path=public&sslmode=disable" \
--to file://schema.hcl \
--dev-url "docker://postgres/15/test"
```
📖 [Declarative workflow docs](https://atlasgo.io/declarative/apply)
### `schema apply`
_**Generate a migration plan and apply it to the database to bring it to the desired state. The desired state can be
specified using a database URL, HCL, SQL, or ORM schema, or a migration directory.**_
```shell
atlas schema apply \
--url mysql://root:pass@:3306/db1 \
--to file://schema.hcl \
--dev-url docker://mysql/8/db1
```
Result
```shell
-- Planned Changes:
-- Modify "users" table
ALTER TABLE `db1`.`users` DROP COLUMN `d`, ADD COLUMN `c` int NOT NULL;
Use the arrow keys to navigate: ↓ ↑ → ←
? Are you sure?:
▸ Apply
Abort
```
📖 [Declarative workflow docs](https://atlasgo.io/declarative/apply)
### `migrate diff`
_**Write a new migration file to the migration directory that brings it to the desired state. The desired state can be
specified using a database URL, HCL, SQL, or ORM schema, or a migration directory.**_
```shell
atlas migrate diff add_blog_posts \
--dir file://migrations \
--to file://schema.hcl \
--dev-url docker://mysql/8/test
```
📖 [Versioned workflow docs](https://atlasgo.io/versioned/diff)
### `migrate apply`
_**Apply all or part of pending migration files in the migration directory on the database.**_
```shell
atlas migrate apply \
--url mysql://root:pass@:3306/db1 \
--dir file://migrations
```
📖 [Versioned workflow docs](https://atlasgo.io/versioned/apply)
## Supported Version Policy
To ensure the best performance, security and compatibility with the Atlas Cloud service, the Atlas team
will only support the two most recent minor versions of the CLI. For example, if the latest version is
`v0.25`, the supported versions will be `v0.24` and `v0.25` (in addition to any patch releases and the
"canary" release which is built twice a day).
## Community
[Documentation](https://atlasgo.io/getting-started) ·
[Discord](https://discord.com/invite/zZ6sWVg6NT) ·
[Twitter](https://twitter.com/atlasgo_io)
[HCL]: https://atlasgo.io/atlas-schema/hcl
[SQL]: https://atlasgo.io/atlas-schema/sql
[ORM]: https://atlasgo.io/orms
================================================
FILE: atlasexec/README.md
================================================
# Atlas SDK for Go
[](https://pkg.go.dev/ariga.io/atlas@master/atlasexec)
An SDK for building ariga/atlas providers in Go.
## Installation
```bash
go get -u ariga.io/atlas@master
```
## How to use
To use the SDK, you need to create a new client with your `migrations` folder and the `atlas` binary path.
```go
package main
import (
...
"ariga.io/atlas/atlasexec"
)
func main() {
// Create a new client
client, err := atlasexec.NewClient("my-migration-folder", "my-atlas-cli-path")
if err != nil {
log.Fatalf("failed to create client: %v", err)
}
}
```
## APIs
For more information, refer to the documentation available at [GoDoc](https://pkg.go.dev/ariga.io/atlas@master/atlasexec#Client)
================================================
FILE: atlasexec/atlas.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec
import (
"bufio"
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"maps"
"os"
"os/exec"
"reflect"
"regexp"
"slices"
"strings"
"sync"
)
type (
// Client is a client for the Atlas CLI.
Client struct {
execPath string
workingDir string
env Environ
stdout io.Writer
stderr io.Writer
}
// LoginParams are the parameters for the `login` command.
LoginParams struct {
Token string
GrantOnly bool // If true, runs `atlas login --grant-only` for offline token flow.
}
// WhoAmIParams are the parameters for the `whoami` command
WhoAmIParams struct {
ConfigURL string
Env string
Vars VarArgs
}
// WhoAmI contains the result of an 'atlas whoami' run.
WhoAmI struct {
Org string `json:"Org,omitempty"`
}
// Version contains the result of an 'atlas version' run.
Version struct {
Version string `json:"Version"`
SHA string `json:"SHA,omitempty"`
Canary bool `json:"Canary,omitempty"`
}
// VarArgs is a map of variables for the command.
VarArgs interface {
// AsArgs returns the variables as arguments.
AsArgs() []string
}
// Vars2 is a map of variables for the command.
// It supports multiple values for the same key (list).
Vars2 map[string]any
// Environ is a map of environment variables.
Environ map[string]string
// RunContext is an input type for describing the context of where the
// command is triggered from. For example, a GitHub Action on the master branch.
RunContext struct {
Repo string `json:"repo,omitempty"`
Path string `json:"path,omitempty"`
Branch string `json:"branch,omitempty"`
Commit string `json:"commit,omitempty"`
URL string `json:"url,omitempty"`
Username string `json:"username,omitempty"` // The username that triggered the event that initiated the command.
UserID string `json:"userID,omitempty"` // The user ID that triggered the event that initiated the command.
SCMType SCMType `json:"scmType,omitempty"` // Source control management system type.
}
// SCMType is a type for the "scm_type" enum field.
SCMType string
// DeployRunContext is an input type for describing the context in which
// `migrate-apply` and `migrate down` were used. For example, a GitHub Action with version v1.2.3
DeployRunContext struct {
TriggerType TriggerType `json:"triggerType,omitempty"`
TriggerVersion string `json:"triggerVersion,omitempty"`
}
// TriggerType defines the type for the "trigger_type" enum field.
TriggerType string
// Vars is a map of variables for the command.
//
// Deprecated: Use Vars2 instead.
Vars map[string]string
)
// TriggerType values.
const (
TriggerTypeCLI TriggerType = "CLI"
TriggerTypeKubernetes TriggerType = "KUBERNETES"
TriggerTypeTerraform TriggerType = "TERRAFORM"
TriggerTypeGithubAction TriggerType = "GITHUB_ACTION"
TriggerTypeCircleCIOrb TriggerType = "CIRCLECI_ORB"
TriggerTypeGitlab TriggerType = "GITLAB"
TriggerTypeBitbucket TriggerType = "BITBUCKET"
TriggerTypeAzureDevOps TriggerType = "AZURE_DEVOPS"
)
// SCMType values.
const (
SCMTypeGithub SCMType = "GITHUB"
SCMTypeGitlab SCMType = "GITLAB"
SCMTypeBitbucket SCMType = "BITBUCKET"
SCMTypeAzureDevOps SCMType = "AZURE_DEVOPS"
)
// ExecutionOrder values.
const (
ExecOrderLinear MigrateExecOrder = "linear" // Default
ExecOrderLinearSkip MigrateExecOrder = "linear-skip"
ExecOrderNonLinear MigrateExecOrder = "non-linear"
)
// NewClient returns a new Atlas client with the given atlas-cli path.
func NewClient(workingDir, execPath string) (_ *Client, err error) {
if execPath == "" {
return nil, fmt.Errorf("execPath cannot be empty")
} else if execPath, err = exec.LookPath(execPath); err != nil {
return nil, fmt.Errorf("looking up atlas-cli: %w", err)
}
if workingDir != "" {
_, err := os.Stat(workingDir)
if err != nil {
return nil, fmt.Errorf("initializing Atlas with working dir %q: %w", workingDir, err)
}
}
return &Client{
execPath: execPath,
workingDir: workingDir,
}, nil
}
// WithWorkDir creates a new client with the given working directory.
// It is useful to run multiple commands in the multiple directories.
//
// Example:
//
// client := atlasexec.NewClient("", "atlas")
// err := client.WithWorkDir("dir1", func(c *atlasexec.Client) error {
// _, err := c.MigrateApply(ctx, &atlasexec.MigrateApplyParams{
// })
// return err
// })
func (c *Client) WithWorkDir(dir string, fn func(*Client) error) error {
wd := c.workingDir
defer func() { c.workingDir = wd }()
c.workingDir = dir
return fn(c)
}
// SetEnv allows we override the environment variables for the atlas-cli.
// To append new environment variables to environment from OS, use NewOSEnviron() then add new variables.
func (c *Client) SetEnv(env map[string]string) error {
for k := range env {
if _, ok := defaultEnvs[k]; ok {
return fmt.Errorf("atlasexec: cannot override the default environment variable %q", k)
}
}
c.env = env
return nil
}
// SetStdout specifies a writer to stream stdout to for every command.
func (c *Client) SetStdout(w io.Writer) {
c.stdout = w
}
// SetStderr specifies a writer to stream stderr to for every command.
func (c *Client) SetStderr(w io.Writer) {
c.stderr = w
}
// Login runs the 'login' command.
func (c *Client) Login(ctx context.Context, params *LoginParams) error {
if params.Token == "" {
return errors.New("token cannot be empty")
}
args := []string{"login", "--token", params.Token}
if params.GrantOnly {
args = append(args, "--grant-only")
}
_, err := c.runCommand(ctx, args)
return err
}
// Logout runs the 'logout' command.
func (c *Client) Logout(ctx context.Context) error {
_, err := c.runCommand(ctx, []string{"logout"})
return err
}
// WhoAmI runs the 'whoami' command.
func (c *Client) WhoAmI(ctx context.Context, params *WhoAmIParams) (*WhoAmI, error) {
args := []string{"whoami", "--format", "{{ json . }}"}
// Global flags
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
return firstResult(jsonDecode[WhoAmI](c.runCommand(ctx, args)))
}
var reVersion = regexp.MustCompile(`^atlas version v(\d+\.\d+.\d+)-?([a-z0-9]*)?`)
// Version runs the 'version' command.
func (c *Client) Version(ctx context.Context) (*Version, error) {
r, err := c.runCommand(ctx, []string{"version"})
if err != nil {
return nil, err
}
out, err := io.ReadAll(r)
if err != nil {
return nil, err
}
v := reVersion.FindSubmatch(out)
if v == nil {
return nil, errors.New("unexpected output format")
}
var sha string
if len(v) > 2 {
sha = string(v[2])
}
return &Version{
Version: string(v[1]),
SHA: sha,
Canary: strings.Contains(string(out), "canary"),
}, nil
}
// var reVersion = regexp.MustCompile(`^atlas version v(\d+\.\d+.\d+)-?([a-z0-9]*)?`)
func (v Version) String() string {
var b strings.Builder
fmt.Fprintf(&b, "atlas version v%s", v.Version)
if v.SHA != "" {
fmt.Fprintf(&b, "-%s", v.SHA)
}
if v.Canary {
b.WriteString("-canary")
}
return b.String()
}
// NewOSEnviron returns the current environment variables from the OS.
func NewOSEnviron() Environ {
env := map[string]string{}
for _, ev := range os.Environ() {
parts := strings.SplitN(ev, "=", 2)
if len(parts) == 0 {
continue
}
k := parts[0]
v := ""
if len(parts) == 2 {
v = parts[1]
}
env[k] = v
}
return env
}
// ToSlice converts the environment variables to a slice.
func (e Environ) ToSlice() []string {
env := make([]string, 0, len(e))
for k, v := range e {
env = append(env, k+"="+v)
}
// Ensure the order of the envs.
slices.Sort(env)
return env
}
var defaultEnvs = map[string]string{
// Disable the update notifier and upgrade suggestions.
"ATLAS_NO_UPDATE_NOTIFIER": "1",
"ATLAS_NO_UPGRADE_SUGGESTIONS": "1",
}
// ErrRequireLogin is returned when a command requires the user to be logged in.
// It exists here to be shared between the different packages that require login.
var ErrRequireLogin = errors.New("command requires 'atlas login'")
// runCommand runs the given command and returns its output.
func (c *Client) runCommand(ctx context.Context, args []string) (io.Reader, error) {
var stdout, stderr bytes.Buffer
cmd := c.cmd(ctx, args)
cmd.Stdout = mergeWriters(&stdout, c.stdout)
cmd.Stderr = mergeWriters(&stderr, c.stderr)
if err := c.runErr(cmd.Run(), &stdout, &stderr); err != nil {
return nil, err
}
return &stdout, nil
}
// Stream is an interface for reading a stream of items.
type Stream[T any] interface {
// Next reads the next item from the stream, making it available by calling Current.
// It returns false if there are no more items and the stream is closed.
Next() bool
// Current returns the current item from the stream.
Current() (T, error)
// Err returns the error, if any, that occurred while reading the stream.
Err() error
}
// runCommandStream runs the given command streams its output split by new-lines.
func (c *Client) runCommandStream(ctx context.Context, args []string) (Stream[string], error) {
cmd := c.cmd(ctx, args)
var stderr bytes.Buffer
cmd.Stderr = mergeWriters(&stderr, c.stderr)
out, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("creating stdout pipe: %w", err)
}
if err = cmd.Start(); err != nil {
return nil, fmt.Errorf("starting command: %w", err)
}
var (
scan = bufio.NewScanner(out)
buf = strings.Builder{}
ch = make(chan string)
s = &stream{ch: ch}
stdout = mergeWriters(&buf, c.stdout)
)
go func() {
defer close(ch)
for scan.Scan() {
stdout.Write(scan.Bytes())
ch <- scan.Text()
}
s.lock.Lock()
defer s.lock.Unlock()
s.err = c.runErr(cmd.Wait(), &buf, &stderr)
}()
return s, nil
}
func (c *Client) cmd(ctx context.Context, args []string) *exec.Cmd {
cmd := exec.CommandContext(ctx, c.execPath, args...) //nolint:gosec
cmd.Dir = c.workingDir
var env Environ
if c.env == nil {
// Initialize the environment variables from the OS.
env = NewOSEnviron()
} else {
env = maps.Clone(c.env)
}
maps.Copy(env, defaultEnvs)
cmd.Env = env.ToSlice()
return cmd
}
func (c *Client) runErr(err error, stdout, stderr interface{ String() string }) error {
if err == nil {
return nil
}
e := strings.TrimSpace(stderr.String())
// Explicit check the stderr for the login error.
if e == "Error: command requires 'atlas login'" {
return ErrRequireLogin
}
return &Error{
err: err,
Stderr: strings.TrimSpace(stderr.String()),
Stdout: strings.TrimSpace(stdout.String()),
}
}
type stream struct {
ch chan string
cur string
err error
lock sync.RWMutex
}
// Next advances the stream to the next item.
func (s *stream) Next() bool {
s.lock.RLock()
if s.err != nil || s.ch == nil {
s.lock.RUnlock()
return false
}
s.lock.RUnlock()
r, ok := <-s.ch
if !ok {
return false
}
s.cur = r
return true
}
// Current returns the current item from the stream.
func (s *stream) Current() (string, error) {
s.lock.RLock()
defer s.lock.RUnlock()
if s.err != nil {
return "", s.err
}
return s.cur, nil
}
// Err returns the error, if any, that occurred while reading the stream.
func (s *stream) Err() error {
s.lock.RLock()
defer s.lock.RUnlock()
return s.err
}
var _ Stream[string] = (*stream)(nil)
func mergeWriters(writers ...io.Writer) io.Writer {
var compact []io.Writer
for _, w := range writers {
if w != nil {
compact = append(compact, w)
}
}
switch len(compact) {
case 1:
return compact[0]
case 0:
return io.Discard
default:
return io.MultiWriter(compact...)
}
}
// Error is an error returned by the atlasexec package,
// when it executes the atlas-cli command.
type Error struct {
err error // The underlying error.
Stdout string // Stdout of the command.
Stderr string // Stderr of the command.
}
// Error implements the error interface.
func (e *Error) Error() string {
if e.Stderr != "" {
return e.Stderr
}
return e.Stdout
}
// ExitCode returns the exit code of the command.
// If the error is not an exec.ExitError, it returns 1.
func (e *Error) ExitCode() int {
var exitErr *exec.ExitError
if errors.As(e.err, &exitErr) {
return exitErr.ExitCode()
}
// Not an exec.ExitError or nil.
// Return the system default exit code.
return new(exec.ExitError).ExitCode()
}
// Unwrap returns the underlying error.
func (e *Error) Unwrap() error {
return e.err
}
// TempFile creates a temporary file with the given content and extension.
func TempFile(content, ext string) (string, func() error, error) {
f, err := os.CreateTemp("", "atlasexec-*."+ext)
if err != nil {
return "", nil, err
}
defer f.Close()
_, err = f.WriteString(content)
if err != nil {
return "", nil, err
}
return fmt.Sprintf("file://%s", f.Name()), func() error {
return os.Remove(f.Name())
}, nil
}
// AsArgs returns the variables as arguments.
func (v Vars2) AsArgs() []string {
keys := make([]string, 0, len(v))
for k := range v {
keys = append(keys, k)
}
slices.Sort(keys)
var args []string
for _, k := range keys {
switch reflect.TypeOf(v[k]).Kind() {
case reflect.Slice, reflect.Array:
ev := reflect.ValueOf(v[k])
for i := range ev.Len() {
args = append(args, "--var", fmt.Sprintf("%s=%v", k, ev.Index(i)))
}
default:
args = append(args, "--var", fmt.Sprintf("%s=%v", k, v[k]))
}
}
return args
}
// AsArgs returns the variables as arguments.
func (v Vars) AsArgs() []string {
var args []string
for k, v := range v {
args = append(args, "--var", fmt.Sprintf("%s=%s", k, v))
}
return args
}
func stringVal(r io.Reader, err error) (string, error) {
if err != nil {
return "", err
}
s, err := io.ReadAll(r)
if err != nil {
return "", err
}
return string(s), nil
}
func jsonDecode[T any](r io.Reader, err error) ([]*T, error) {
if err != nil {
return nil, err
}
buf, err := io.ReadAll(r)
if err != nil {
return nil, err
}
var dst []*T
dec := json.NewDecoder(bytes.NewReader(buf))
for {
var m T
switch err := dec.Decode(&m); err {
case io.EOF:
return dst, nil
case nil:
dst = append(dst, &m)
default:
return nil, &Error{
err: fmt.Errorf("decoding JSON from stdout: %w", err),
Stdout: string(buf),
}
}
}
}
func jsonDecodeErr[T any](fn func([]*T, string) error) func(io.Reader, error) ([]*T, error) {
return func(r io.Reader, err error) ([]*T, error) {
if err != nil {
if cliErr := (&Error{}); errors.As(err, &cliErr) && cliErr.Stdout != "" {
d, err := jsonDecode[T](strings.NewReader(cliErr.Stdout), nil)
if err == nil {
return nil, fn(d, cliErr.Stderr)
}
// If the error is not a JSON, return the original error.
}
return nil, err
}
return jsonDecode[T](r, err)
}
}
// repeatFlag repeats the flag for each value.
func repeatFlag(flag string, values []string) []string {
if len(values) == 0 {
return nil
}
out := make([]string, 0, len(values)*2)
for _, v := range values {
out = append(out, flag, v)
}
return out
}
func listString(args []string) string {
return strings.Join(args, ",")
}
func firstResult[T ~[]E, E any](r T, err error) (e E, _ error) {
switch {
case err != nil:
return e, err
case len(r) == 1:
return r[0], nil
default:
return e, errors.New("The command returned more than one result, use Slice function instead")
}
}
func last[A ~[]E, E any](a A) (_ E) {
if l := len(a); l > 0 {
return a[l-1]
}
return
}
================================================
FILE: atlasexec/atlas_internal_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec
import (
"context"
"io"
"testing"
"github.com/stretchr/testify/require"
)
func TestEnv(t *testing.T) {
// printenv is a simple command that prints all environment variables
c, err := NewClient(t.TempDir(), "printenv")
require.NoError(t, err)
// Should not be able to override the default environment variable
require.ErrorContains(t, c.SetEnv(map[string]string{
"FOO": "bar",
"ATLAS_NO_UPDATE_NOTIFIER": "0",
}), "cannot override the default environment variable")
// Should be able to set new environment variables
require.NoError(t, c.SetEnv(map[string]string{
"FOO": "bar",
"BAZ": "qux",
}))
// Invoke the command and check the environment variables
v, err := c.runCommand(context.Background(), nil)
require.NoError(t, err)
raw, err := io.ReadAll(v)
require.NoError(t, err)
require.Equal(t, `ATLAS_NO_UPDATE_NOTIFIER=1
ATLAS_NO_UPGRADE_SUGGESTIONS=1
BAZ=qux
FOO=bar
`, string(raw))
}
================================================
FILE: atlasexec/atlas_migrate.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"strconv"
"strings"
"time"
)
type (
// MigrateApplyParams are the parameters for the `migrate apply` command.
MigrateApplyParams struct {
ConfigURL string
Env string
Vars VarArgs
Context *DeployRunContext
DirURL string
URL string
RevisionsSchema string
BaselineVersion string
TxMode string
ExecOrder MigrateExecOrder
Amount uint64
ToVersion string
AllowDirty bool
DryRun bool
LockName string
}
// MigrateApply contains a summary of a migration applying attempt on a database.
MigrateApply struct {
Env
Pending []File `json:"Pending,omitempty"` // Pending migration files
Applied []*AppliedFile `json:"Applied,omitempty"` // Applied files
Current string `json:"Current,omitempty"` // Current migration version
Target string `json:"Target,omitempty"` // Target migration version
Start time.Time
End time.Time
// Error is set even then, if it was not caused by a statement in a migration file,
// but by Atlas, e.g. when committing or rolling back a transaction.
Error string `json:"Error,omitempty"`
}
// MigrateApplyError is returned when an error occurred
// during a migration applying attempt.
MigrateApplyError struct {
Result []*MigrateApply
Stderr string
}
// MigrateExecOrder define how Atlas computes and executes pending migration files to the database.
// See: https://atlasgo.io/versioned/apply#execution-order
MigrateExecOrder string
// MigrateDownParams are the parameters for the `migrate down` command.
MigrateDownParams struct {
ConfigURL string
Env string
Vars VarArgs
Context *DeployRunContext
DevURL string
DirURL string
URL string
RevisionsSchema string
Amount uint64
ToVersion string
ToTag string
// Not yet supported
// DryRun bool
// TxMode string
}
// MigrateDown contains a summary of a migration down attempt on a database.
MigrateDown struct {
Planned []File `json:"Planned,omitempty"` // Planned migration files
Reverted []*RevertedFile `json:"Reverted,omitempty"` // Reverted files
Current string `json:"Current,omitempty"` // Current migration version
Target string `json:"Target,omitempty"` // Target migration version
Total int `json:"Total,omitempty"` // Total number of migrations to revert
Start time.Time
End time.Time
// URL and Status are set only when the migration is planned or executed in the cloud.
URL string `json:"URL,omitempty"`
Status string `json:"Status,omitempty"`
// Error is set even then, if it was not caused by a statement in a migration file,
// but by Atlas, e.g. when committing or rolling back a transaction.
Error string `json:"Error,omitempty"`
}
// MigratePushParams are the parameters for the `migrate push` command.
MigratePushParams struct {
ConfigURL string
Env string
Vars VarArgs
Context *RunContext
DevURL string
Name string
Tag string
DirURL string
DirFormat string
LockTimeout string
}
// MigrateLintParams are the parameters for the `migrate lint` command.
MigrateLintParams struct {
ConfigURL string
Env string
Vars VarArgs
Context *RunContext
Format string
DevURL string
GitBase string
GitDir string
DirURL string
Latest uint64
Writer io.Writer
Base string
Web bool
}
// MigrateHashParams are the parameters for the `migrate hash` command.
MigrateHashParams struct {
ConfigURL string
Env string
Vars VarArgs
DirURL string
DirFormat string
}
// MigrateRebaseParams are the parameters for the `migrate rebase` command.
MigrateRebaseParams struct {
ConfigURL string
Env string
Vars VarArgs
DirURL string
Files []string
}
// MigrateTestParams are the parameters for the `migrate test` command.
MigrateTestParams struct {
ConfigURL string
Env string
Vars VarArgs
Context *RunContext
DevURL string
DirURL string
DirFormat string
Run string
RevisionsSchema string
Paths []string
}
// MigrateStatusParams are the parameters for the `migrate status` command.
MigrateStatusParams struct {
ConfigURL string
Env string
Vars VarArgs
DirURL string
URL string
RevisionsSchema string
}
// MigrateLsParams are the parameters for the `migrate ls` command.
MigrateLsParams struct {
ConfigURL string
Env string
Vars VarArgs
DirURL string
Short bool // -s: print only migration version (omit description and .sql suffix)
Latest bool // -l: print only the latest migration file
}
// MigrateSetParams are the parameters for the `migrate set` command.
MigrateSetParams struct {
ConfigURL string
Env string
Vars VarArgs
DirURL string
URL string
RevisionsSchema string
Version string
}
// MigrateDiffParams are the parameters for the `migrate diff` command.
MigrateDiffParams struct {
ConfigURL string
Env string
Vars VarArgs
Name string
ToURL string
DevURL string
DirURL string
DirFormat string
Schema []string
LockTimeout string
Format string
Qualifier string
}
// MigrateDiff contains the result of the `migrate diff` command.
MigrateDiff struct {
Files []File `json:"Files,omitempty"` // Generated migration files
Dir string `json:"Dir,omitempty"` // Path to migration directory
}
// MigrateStatus contains a summary of the migration status of a database.
MigrateStatus struct {
Env Env `json:"Env,omitempty"` // Environment info.
Available []File `json:"Available,omitempty"` // Available migration files
Pending []File `json:"Pending,omitempty"` // Pending migration files
Applied []*Revision `json:"Applied,omitempty"` // Applied migration files
Current string `json:"Current,omitempty"` // Current migration version
Next string `json:"Next,omitempty"` // Next migration version
Count int `json:"Count,omitempty"` // Count of applied statements of the last revision
Total int `json:"Total,omitempty"` // Total statements of the last migration
Status string `json:"Status,omitempty"` // Status of migration (OK, PENDING)
Error string `json:"Error,omitempty"` // Last Error that occurred
SQL string `json:"SQL,omitempty"` // SQL that caused the last Error
}
)
// MigratePush runs the 'migrate push' command.
func (c *Client) MigratePush(ctx context.Context, params *MigratePushParams) (string, error) {
args := []string{"migrate", "push"}
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if params.DirURL != "" {
args = append(args, "--dir", params.DirURL)
}
if params.DirFormat != "" {
args = append(args, "--dir-format", params.DirFormat)
}
if params.LockTimeout != "" {
args = append(args, "--lock-timeout", params.LockTimeout)
}
if params.Context != nil {
buf, err := json.Marshal(params.Context)
if err != nil {
return "", err
}
args = append(args, "--context", string(buf))
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
if params.Name == "" {
return "", errors.New("directory name cannot be empty")
}
if params.Tag != "" {
args = append(args, fmt.Sprintf("%s:%s", params.Name, params.Tag))
} else {
args = append(args, params.Name)
}
resp, err := stringVal(c.runCommand(ctx, args))
return strings.TrimSpace(resp), err
}
// MigrateApply runs the 'migrate apply' command.
func (c *Client) MigrateApply(ctx context.Context, params *MigrateApplyParams) (*MigrateApply, error) {
return firstResult(c.MigrateApplySlice(ctx, params))
}
// MigrateApplySlice runs the 'migrate apply' command for multiple targets.
func (c *Client) MigrateApplySlice(ctx context.Context, params *MigrateApplyParams) ([]*MigrateApply, error) {
args := []string{"migrate", "apply", "--format", "{{ json . }}"}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Context != nil {
buf, err := json.Marshal(params.Context)
if err != nil {
return nil, err
}
args = append(args, "--context", string(buf))
}
if params.URL != "" {
args = append(args, "--url", params.URL)
}
if params.DirURL != "" {
args = append(args, "--dir", params.DirURL)
}
if params.AllowDirty {
args = append(args, "--allow-dirty")
}
if params.DryRun {
args = append(args, "--dry-run")
}
if params.RevisionsSchema != "" {
args = append(args, "--revisions-schema", params.RevisionsSchema)
}
if params.BaselineVersion != "" {
args = append(args, "--baseline", params.BaselineVersion)
}
if params.TxMode != "" {
args = append(args, "--tx-mode", params.TxMode)
}
if params.ExecOrder != "" {
args = append(args, "--exec-order", string(params.ExecOrder))
}
if params.ToVersion != "" {
args = append(args, "--to-version", params.ToVersion)
}
if params.Amount > 0 {
args = append(args, strconv.FormatUint(params.Amount, 10))
}
if params.LockName != "" {
args = append(args, "--lock-name", params.LockName)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
return jsonDecodeErr(newMigrateApplyError)(c.runCommand(ctx, args))
}
// MigrateDown runs the 'migrate down' command.
func (c *Client) MigrateDown(ctx context.Context, params *MigrateDownParams) (*MigrateDown, error) {
args := []string{"migrate", "down", "--format", "{{ json . }}"}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if params.Context != nil {
buf, err := json.Marshal(params.Context)
if err != nil {
return nil, err
}
args = append(args, "--context", string(buf))
}
if params.URL != "" {
args = append(args, "--url", params.URL)
}
if params.DirURL != "" {
args = append(args, "--dir", params.DirURL)
}
if params.RevisionsSchema != "" {
args = append(args, "--revisions-schema", params.RevisionsSchema)
}
if params.ToVersion != "" {
args = append(args, "--to-version", params.ToVersion)
}
if params.ToTag != "" {
args = append(args, "--to-tag", params.ToTag)
}
if params.Amount > 0 {
args = append(args, strconv.FormatUint(params.Amount, 10))
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
r, err := c.runCommand(ctx, args)
if cliErr := (&Error{}); errors.As(err, &cliErr) && cliErr.Stderr == "" {
r = strings.NewReader(cliErr.Stdout)
err = nil
}
// NOTE: This command only support one result.
return firstResult(jsonDecode[MigrateDown](r, err))
}
// MigrateTest runs the 'migrate test' command.
func (c *Client) MigrateTest(ctx context.Context, params *MigrateTestParams) (string, error) {
args := []string{"migrate", "test"}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.DirURL != "" {
args = append(args, "--dir", params.DirURL)
}
if params.DirFormat != "" {
args = append(args, "--dir-format", params.DirFormat)
}
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if params.Context != nil {
buf, err := json.Marshal(params.Context)
if err != nil {
return "", err
}
args = append(args, "--context", string(buf))
}
if params.RevisionsSchema != "" {
args = append(args, "--revisions-schema", params.RevisionsSchema)
}
if params.Run != "" {
args = append(args, "--run", params.Run)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
if len(params.Paths) > 0 {
args = append(args, params.Paths...)
}
return stringVal(c.runCommand(ctx, args))
}
// MigrateStatus runs the 'migrate status' command.
func (c *Client) MigrateStatus(ctx context.Context, params *MigrateStatusParams) (*MigrateStatus, error) {
args := []string{"migrate", "status", "--format", "{{ json . }}"}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.URL != "" {
args = append(args, "--url", params.URL)
}
if params.DirURL != "" {
args = append(args, "--dir", params.DirURL)
}
if params.RevisionsSchema != "" {
args = append(args, "--revisions-schema", params.RevisionsSchema)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
// NOTE: This command only support one result.
return firstResult(jsonDecode[MigrateStatus](c.runCommand(ctx, args)))
}
// MigrateLs runs the 'migrate ls' command and returns the listed migration file names (or versions when Short is true), one per line.
func (c *Client) MigrateLs(ctx context.Context, params *MigrateLsParams) (string, error) {
args := []string{"migrate", "ls"}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.DirURL != "" {
args = append(args, "--dir", params.DirURL)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
if params.Short {
args = append(args, "--short")
}
if params.Latest {
args = append(args, "--latest")
}
return stringVal(c.runCommand(ctx, args))
}
// MigrateSet runs the 'migrate set' command.
func (c *Client) MigrateSet(ctx context.Context, params *MigrateSetParams) error {
args := []string{"migrate", "set"}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.URL != "" {
args = append(args, "--url", params.URL)
}
if params.DirURL != "" {
args = append(args, "--dir", params.DirURL)
}
if params.RevisionsSchema != "" {
args = append(args, "--revisions-schema", params.RevisionsSchema)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
if params.Version != "" {
args = append(args, params.Version)
}
_, err := c.runCommand(ctx, args)
return err
}
// MigrateDiff runs the 'migrate diff --dry-run' command and returns the generated migration files without changing the filesystem.
// Requires atlas CLI to be logged in to the cloud.
func (c *Client) MigrateDiff(ctx context.Context, params *MigrateDiffParams) (*MigrateDiff, error) {
args := []string{"migrate", "diff", "--dry-run"}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.ToURL != "" {
args = append(args, "--to", params.ToURL)
}
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if params.DirURL != "" {
args = append(args, "--dir", params.DirURL)
}
if params.DirFormat != "" {
args = append(args, "--dir-format", params.DirFormat)
}
if params.LockTimeout != "" {
args = append(args, "--lock-timeout", params.LockTimeout)
}
if params.Qualifier != "" {
args = append(args, "--qualifier", params.Qualifier)
}
if len(params.Schema) > 0 {
args = append(args, "--schema", strings.Join(params.Schema, ","))
}
if params.Format != "" {
args = append(args, "--format", params.Format)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
if params.Name != "" {
args = append(args, params.Name)
}
v, err := jsonDecode[MigrateDiff](c.runCommand(ctx, args))
var e *Error
switch {
// if jsonDecode returns an error, and stderr is empty, it means the migration is synced with the desired state.
case errors.As(err, &e) && e.Stderr == "":
return &MigrateDiff{}, nil
case err != nil:
return nil, err
}
return firstResult(v, nil)
}
// MigrateLint runs the 'migrate lint' command.
func (c *Client) MigrateLint(ctx context.Context, params *MigrateLintParams) (*SummaryReport, error) {
if params.Writer != nil || params.Web {
return nil, errors.New("atlasexec: Writer or Web reporting are not supported with MigrateLint, use MigrateLintError")
}
args, err := params.AsArgs()
if err != nil {
return nil, err
}
r, err := c.runCommand(ctx, args)
if cliErr := (&Error{}); errors.As(err, &cliErr) && cliErr.Stderr == "" {
r = strings.NewReader(cliErr.Stdout)
err = nil
}
// NOTE: This command only support one result.
return firstResult(jsonDecode[SummaryReport](r, err))
}
// MigrateHash runs the 'migrate hash' command.
func (c *Client) MigrateHash(ctx context.Context, params *MigrateHashParams) error {
args := []string{"migrate", "hash"}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
if params.DirURL != "" {
args = append(args, "--dir", params.DirURL)
}
if params.DirFormat != "" {
args = append(args, "--dir-format", params.DirFormat)
}
_, err := c.runCommand(ctx, args)
return err
}
// MigrateRebase runs the 'migrate rebase' command.
func (c *Client) MigrateRebase(ctx context.Context, params *MigrateRebaseParams) error {
args := []string{"migrate", "rebase"}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
if params.DirURL != "" {
args = append(args, "--dir", params.DirURL)
}
args = append(args, params.Files...)
_, err := c.runCommand(ctx, args)
return err
}
// MigrateLintError runs the 'migrate lint' command, the output is written to params.Writer and reports
// if an error occurred. If the error is a setup error, a Error is returned. If the error is a lint error,
// LintErr is returned.
func (c *Client) MigrateLintError(ctx context.Context, params *MigrateLintParams) error {
args, err := params.AsArgs()
if err != nil {
return err
}
r, err := c.runCommand(ctx, args)
var (
cliErr *Error
isCLI = errors.As(err, &cliErr)
)
// Setup errors.
if isCLI && cliErr.Stderr != "" {
return cliErr
}
// Lint errors.
if isCLI && cliErr.Stdout != "" {
err = ErrLint
r = strings.NewReader(cliErr.Stdout)
}
// Unknown errors.
if err != nil && !isCLI {
return err
}
if params.Writer != nil && r != nil {
if _, ioErr := io.Copy(params.Writer, r); ioErr != nil {
err = errors.Join(err, ioErr)
}
}
return err
}
// AsArgs returns the parameters as arguments.
func (p *MigrateLintParams) AsArgs() ([]string, error) {
args := []string{"migrate", "lint"}
if p.Web {
args = append(args, "-w")
}
if p.Context != nil {
buf, err := json.Marshal(p.Context)
if err != nil {
return nil, err
}
args = append(args, "--context", string(buf))
}
if p.Env != "" {
args = append(args, "--env", p.Env)
}
if p.ConfigURL != "" {
args = append(args, "--config", p.ConfigURL)
}
if p.DevURL != "" {
args = append(args, "--dev-url", p.DevURL)
}
if p.DirURL != "" {
args = append(args, "--dir", p.DirURL)
}
if p.Base != "" {
args = append(args, "--base", p.Base)
}
if p.Latest > 0 {
args = append(args, "--latest", strconv.FormatUint(p.Latest, 10))
}
if p.GitBase != "" {
args = append(args, "--git-base", p.GitBase)
}
if p.GitDir != "" {
args = append(args, "--git-dir", p.GitDir)
}
if p.Vars != nil {
args = append(args, p.Vars.AsArgs()...)
}
format := "{{ json . }}"
if p.Format != "" {
format = p.Format
}
args = append(args, "--format", format)
return args, nil
}
// Summary of the migration attempt.
func (a *MigrateApply) Summary(ident string) string {
var (
passedC, failedC int
passedS, failedS int
passedF, failedF int
lines = make([]string, 0, 3)
)
for _, f := range a.Applied {
// For each check file, count the
// number of failed assertions.
for _, cf := range f.Checks {
for _, s := range cf.Stmts {
if s.Error != nil {
failedC++
} else {
passedC++
}
}
}
passedS += len(f.Applied)
if f.Error != nil {
failedF++
// Last statement failed (not an assertion).
if len(f.Checks) == 0 || f.Checks[len(f.Checks)-1].Error == nil {
passedS--
failedS++
}
} else {
passedF++
}
}
// Execution time.
lines = append(lines, a.End.Sub(a.Start).String())
// Executed files.
switch {
case passedF > 0 && failedF > 0:
lines = append(lines, fmt.Sprintf("%d migration%s ok, %d with errors", passedF, plural(passedF), failedF))
case passedF > 0:
lines = append(lines, fmt.Sprintf("%d migration%s", passedF, plural(passedF)))
case failedF > 0:
lines = append(lines, fmt.Sprintf("%d migration%s with errors", failedF, plural(failedF)))
}
// Executed checks.
switch {
case passedC > 0 && failedC > 0:
lines = append(lines, fmt.Sprintf("%d check%s ok, %d failure%s", passedC, plural(passedC), failedC, plural(failedC)))
case passedC > 0:
lines = append(lines, fmt.Sprintf("%d check%s", passedC, plural(passedC)))
case failedC > 0:
lines = append(lines, fmt.Sprintf("%d check error%s", failedC, plural(failedC)))
}
// Executed statements.
switch {
case passedS > 0 && failedS > 0:
lines = append(lines, fmt.Sprintf("%d sql statement%s ok, %d with errors", passedS, plural(passedS), failedS))
case passedS > 0:
lines = append(lines, fmt.Sprintf("%d sql statement%s", passedS, plural(passedS)))
case failedS > 0:
lines = append(lines, fmt.Sprintf("%d sql statement%s with errors", failedS, plural(failedS)))
}
var b strings.Builder
for i, l := range lines {
b.WriteString("-")
b.WriteByte(' ')
b.WriteString(fmt.Sprintf("**%s**", l))
if i < len(lines)-1 {
b.WriteByte('\n')
b.WriteString(ident)
}
}
return b.String()
}
var (
// ErrLint is returned when the 'migrate lint' finds a diagnostic that is configured to
// be reported as an error, such as destructive changes by default.
ErrLint = errors.New("lint error")
// Deprecated: Use ErrLint instead.
LintErr = ErrLint
)
// LatestVersion returns the latest version of the migration directory.
func (r MigrateStatus) LatestVersion() string {
if l := len(r.Available); l > 0 {
return r.Available[l-1].Version
}
return ""
}
// Amount returns the number of migrations need to apply
// for the given version.
//
// The second return value is true if the version is found
// and the database is up-to-date.
//
// If the version is not found, it returns 0 and the second
// return value is false.
func (r MigrateStatus) Amount(version string) (amount uint64, ok bool) {
if version == "" {
amount := uint64(len(r.Pending))
return amount, amount == 0
}
if r.Current == version {
return amount, true
}
for idx, v := range r.Pending {
if v.Version == version {
amount = uint64(idx + 1) //nolint:gosec //G115: Safe conversion as idx is from range
break
}
}
return amount, false
}
func newMigrateApplyError(r []*MigrateApply, stderr string) error {
return &MigrateApplyError{Result: r, Stderr: stderr}
}
// Error implements the error interface.
func (e *MigrateApplyError) Error() string {
var errs []string
for _, r := range e.Result {
if r.Error != "" {
errs = append(errs, r.Error)
}
}
if e.Stderr != "" {
errs = append(errs, e.Stderr)
}
return strings.Join(errs, "\n")
}
func plural(n int) (s string) {
if n > 1 {
s += "s"
}
return
}
================================================
FILE: atlasexec/atlas_migrate_example_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec_test
import (
"context"
"fmt"
"log"
"os"
"ariga.io/atlas/atlasexec"
)
func ExampleClient_MigrateApply() {
// Define the execution context, supplying a migration directory
// and potentially an `atlas.hcl` configuration file using `atlasexec.WithHCL`.
workdir, err := atlasexec.NewWorkingDir(
atlasexec.WithMigrations(
os.DirFS("./migrations"),
),
)
if err != nil {
log.Fatalf("failed to load working directory: %v", err)
}
// atlasexec works on a temporary directory, so we need to close it
defer workdir.Close()
// Initialize the client.
client, err := atlasexec.NewClient(workdir.Path(), "atlas")
if err != nil {
log.Fatalf("failed to initialize client: %v", err)
}
// Run `atlas migrate apply` on a SQLite database under /tmp.
res, err := client.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{
URL: "sqlite:///tmp/demo.db?_fk=1&cache=shared",
})
if err != nil {
log.Fatalf("failed to apply migrations: %v", err)
}
fmt.Printf("Applied %d migrations\n", len(res.Applied))
}
func ExampleClient_MigrateSet() {
// Define the execution context, supplying a migration directory
// and potentially an `atlas.hcl` configuration file using `atlasexec.WithHCL`.
workdir, err := atlasexec.NewWorkingDir(
atlasexec.WithMigrations(
os.DirFS("./migrations"),
),
)
if err != nil {
log.Fatalf("failed to load working directory: %v", err)
}
// atlasexec works on a temporary directory, so we need to close it
defer workdir.Close()
// Initialize the client.
client, err := atlasexec.NewClient(workdir.Path(), "atlas")
if err != nil {
log.Fatalf("failed to initialize client: %v", err)
}
// Run `atlas migrate set` to mark migrations as applied up to version "3".
err = client.MigrateSet(context.Background(), &atlasexec.MigrateSetParams{
URL: "sqlite:///tmp/demo.db?_fk=1&cache=shared",
Version: "3",
})
if err != nil {
log.Fatalf("failed to set migrations: %v", err)
}
fmt.Println("Migration version set successfully")
}
================================================
FILE: atlasexec/atlas_migrate_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec_test
import (
"bytes"
"context"
"database/sql"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"ariga.io/atlas/atlasexec"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/sqlcheck"
"github.com/stretchr/testify/require"
)
func TestMigrate_Status(t *testing.T) {
type args struct {
ctx context.Context
data *atlasexec.MigrateStatusParams
}
tests := []struct {
name string
args args
wantCurrent string
wantNext string
wantErr bool
}{
{
args: args{
ctx: context.Background(),
data: &atlasexec.MigrateStatusParams{
DirURL: "file://testdata/migrations",
},
},
wantCurrent: "No migration applied yet",
wantNext: "20230727105553",
},
}
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(wd, "atlas")
require.NoError(t, err)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.data.URL = sqlitedb(t, "")
got, err := c.MigrateStatus(tt.args.ctx, tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("migrateStatus() error = %v, wantErr %v", err, tt.wantErr)
return
}
require.Equal(t, tt.wantCurrent, got.Current)
require.Equal(t, tt.wantNext, got.Next)
})
}
}
func TestMigrate_Apply(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
for _, tt := range []struct {
name string
params *atlasexec.MigrateApplyParams
args string
stdout string
}{
{
name: "no params",
params: &atlasexec.MigrateApplyParams{},
args: "migrate apply --format {{ json . }}",
stdout: `{"Driver":"mysql"}`,
},
{
name: "with env",
params: &atlasexec.MigrateApplyParams{
Env: "test",
},
args: "migrate apply --format {{ json . }} --env test",
stdout: `{"Driver":"mysql"}`,
},
{
name: "with url",
params: &atlasexec.MigrateApplyParams{
URL: "sqlite://file?_fk=1&cache=shared&mode=memory",
},
args: "migrate apply --format {{ json . }} --url sqlite://file?_fk=1&cache=shared&mode=memory",
stdout: `{"Driver":"mysql"}`,
},
{
name: "with exec order",
params: &atlasexec.MigrateApplyParams{
ExecOrder: atlasexec.ExecOrderLinear,
},
args: "migrate apply --format {{ json . }} --exec-order linear",
stdout: `{"Driver":"mysql"}`,
},
{
name: "with lock name",
params: &atlasexec.MigrateApplyParams{
LockName: "custom_lock",
},
args: "migrate apply --format {{ json . }} --lock-name custom_lock",
stdout: `{"Driver":"mysql"}`,
},
} {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", tt.stdout)
result, err := c.MigrateApply(context.Background(), tt.params)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, "mysql", result.Driver)
})
}
}
func TestMigrate_Ls(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
for _, tt := range []struct {
name string
params *atlasexec.MigrateLsParams
args string
stdout string
}{
{
name: "no params",
params: &atlasexec.MigrateLsParams{},
args: "migrate ls",
stdout: "\n",
},
{
name: "with dir",
params: &atlasexec.MigrateLsParams{
DirURL: "file://migrations",
},
args: "migrate ls --dir file://migrations",
stdout: "\n",
},
{
name: "with short",
params: &atlasexec.MigrateLsParams{
Short: true,
},
args: "migrate ls --short",
stdout: "\n",
},
{
name: "with latest",
params: &atlasexec.MigrateLsParams{
Latest: true,
},
args: "migrate ls --latest",
stdout: "\n",
},
{
name: "with short and latest",
params: &atlasexec.MigrateLsParams{
DirURL: "file://migrations",
Short: true,
Latest: true,
},
args: "migrate ls --dir file://migrations --short --latest",
stdout: "20230727105615\n",
},
{
name: "with config and env",
params: &atlasexec.MigrateLsParams{
ConfigURL: "file://atlas.hcl",
Env: "dev",
},
args: "migrate ls --config file://atlas.hcl --env dev",
stdout: "\n",
},
} {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", tt.stdout)
got, err := c.MigrateLs(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, tt.stdout, got)
})
}
}
func TestMigrate_Ls_Integration(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(wd, "atlas")
require.NoError(t, err)
dirURL := "file://testdata/migrations"
out, err := c.MigrateLs(context.Background(), &atlasexec.MigrateLsParams{DirURL: dirURL})
if err != nil {
if strings.Contains(err.Error(), "unknown") || strings.Contains(err.Error(), "unknown command") {
t.Skip("atlas binary does not support 'migrate ls' (e.g. OSS build)")
}
require.NoError(t, err)
}
lines := strings.Split(strings.TrimSpace(out), "\n")
require.GreaterOrEqual(t, len(lines), 2)
require.Contains(t, out, "20230727105553_init.sql")
require.Contains(t, out, "20230727105615_t2.sql")
outShort, err := c.MigrateLs(context.Background(), &atlasexec.MigrateLsParams{DirURL: dirURL, Short: true})
if err != nil && strings.Contains(err.Error(), "unknown flag") {
t.Skip("atlas binary does not support --short/--latest (use enterprise or newer build)")
}
require.NoError(t, err)
require.Contains(t, outShort, "20230727105553")
require.Contains(t, outShort, "20230727105615")
require.NotContains(t, outShort, ".sql")
outLatest, err := c.MigrateLs(context.Background(), &atlasexec.MigrateLsParams{DirURL: dirURL, Latest: true})
require.NoError(t, err)
require.Equal(t, 1, len(strings.Split(strings.TrimSpace(outLatest), "\n")))
require.Contains(t, outLatest, "20230926085734_destructive-change.sql")
}
func TestMigrate_Set(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
for _, tt := range []struct {
name string
params *atlasexec.MigrateSetParams
args string
}{
{
name: "no params",
params: &atlasexec.MigrateSetParams{},
args: "migrate set",
},
{
name: "with env",
params: &atlasexec.MigrateSetParams{
Env: "test",
},
args: "migrate set --env test",
},
{
name: "with url",
params: &atlasexec.MigrateSetParams{
URL: "sqlite://file?_fk=1&cache=shared&mode=memory",
},
args: "migrate set --url sqlite://file?_fk=1&cache=shared&mode=memory",
},
{
name: "with dir",
params: &atlasexec.MigrateSetParams{
DirURL: "file://migrations",
},
args: "migrate set --dir file://migrations",
},
{
name: "with revisions-schema",
params: &atlasexec.MigrateSetParams{
RevisionsSchema: "my_revisions",
},
args: "migrate set --revisions-schema my_revisions",
},
{
name: "with version",
params: &atlasexec.MigrateSetParams{
Version: "3",
},
args: "migrate set 3",
},
{
name: "with all params",
params: &atlasexec.MigrateSetParams{
URL: "sqlite://file?_fk=1&cache=shared&mode=memory",
DirURL: "file://migrations",
RevisionsSchema: "my_revisions",
Version: "1.2.4",
},
args: "migrate set --url sqlite://file?_fk=1&cache=shared&mode=memory --dir file://migrations --revisions-schema my_revisions 1.2.4",
},
} {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", "ok")
err := c.MigrateSet(context.Background(), tt.params)
require.NoError(t, err)
})
}
}
func TestMigrate_Down(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
for _, tt := range []struct {
name string
params *atlasexec.MigrateDownParams
args string
stdout string
}{
{
name: "no params",
params: &atlasexec.MigrateDownParams{},
args: "migrate down --format {{ json . }}",
stdout: `{"Status":"Pending"}`,
},
{
name: "with env",
params: &atlasexec.MigrateDownParams{
Env: "test",
},
args: "migrate down --format {{ json . }} --env test",
stdout: `{"Status":"Pending"}`,
},
{
name: "with url",
params: &atlasexec.MigrateDownParams{
URL: "sqlite://file?_fk=1&cache=shared&mode=memory",
},
args: "migrate down --format {{ json . }} --url sqlite://file?_fk=1&cache=shared&mode=memory",
stdout: `{"Status":"Pending"}`,
},
{
name: "with target version",
params: &atlasexec.MigrateDownParams{
ToVersion: "12345",
},
args: "migrate down --format {{ json . }} --to-version 12345",
stdout: `{"Status":"Pending"}`,
},
{
name: "with tag version",
params: &atlasexec.MigrateDownParams{
ToTag: "12345",
},
args: "migrate down --format {{ json . }} --to-tag 12345",
stdout: `{"Status":"Pending"}`,
},
{
name: "with amount",
params: &atlasexec.MigrateDownParams{
Amount: 10,
},
args: "migrate down --format {{ json . }} 10",
stdout: `{"Status":"Pending"}`,
},
{
name: "dev-url",
params: &atlasexec.MigrateDownParams{
DevURL: "url",
},
args: "migrate down --format {{ json . }} --dev-url url",
stdout: `{"Status":"Pending"}`,
},
} {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", tt.stdout)
result, err := c.MigrateDown(context.Background(), tt.params)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, "Pending", result.Status)
})
}
}
func TestMigrate_Test(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
for _, tt := range []struct {
name string
params *atlasexec.MigrateTestParams
args string
stdout string
}{
{
name: "no params",
params: &atlasexec.MigrateTestParams{},
args: "migrate test",
stdout: "test result",
},
{
name: "with env",
params: &atlasexec.MigrateTestParams{
Env: "test",
},
args: "migrate test --env test",
stdout: "test result",
},
{
name: "with config",
params: &atlasexec.MigrateTestParams{
ConfigURL: "file://config.hcl",
},
args: "migrate test --config file://config.hcl",
stdout: "test result",
},
{
name: "with dev-url",
params: &atlasexec.MigrateTestParams{
DevURL: "sqlite://file?_fk=1&cache=shared&mode=memory",
},
args: "migrate test --dev-url sqlite://file?_fk=1&cache=shared&mode=memory",
stdout: "test result",
},
{
name: "with run",
params: &atlasexec.MigrateTestParams{
Run: "example",
},
args: "migrate test --run example",
stdout: "test result",
},
{
name: "with run and paths",
params: &atlasexec.MigrateTestParams{
Run: "example",
Paths: []string{"./foo", "./bar"},
},
args: "migrate test --run example ./foo ./bar",
stdout: "test result",
},
{
name: "with revisions-schema",
params: &atlasexec.MigrateTestParams{
RevisionsSchema: "schema",
},
args: "migrate test --revisions-schema schema",
stdout: "test result",
},
{
name: "with run context",
params: &atlasexec.MigrateTestParams{
Context: &atlasexec.RunContext{
Repo: "testing-repo",
},
},
args: "migrate test --context {\"repo\":\"testing-repo\"}",
stdout: "test result",
},
} {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", tt.stdout)
result, err := c.MigrateTest(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, tt.stdout, result)
})
}
}
func TestAtlasMigrate_ApplyBroken(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
got, err := c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{
URL: "sqlite://?mode=memory",
DirURL: "file://testdata/broken",
})
require.ErrorContains(t, err, `sql/migrate: executing statement "broken;" from version "20231029112426": near "broken": syntax error`)
require.Nil(t, got)
report, ok := err.(*atlasexec.MigrateApplyError)
require.True(t, ok)
require.Equal(t, "20231029112426", report.Result[0].Target)
require.Equal(t, "sql/migrate: executing statement \"broken;\" from version \"20231029112426\": near \"broken\": syntax error", report.Error())
require.Len(t, report.Result[0].Applied, 1)
require.Equal(t, &struct {
Stmt, Text string
}{
Stmt: "broken;",
Text: "near \"broken\": syntax error",
}, report.Result[0].Applied[0].Error)
}
func TestMigrateApplyError_Error(t *testing.T) {
t.Run("single result error only", func(t *testing.T) {
e := &atlasexec.MigrateApplyError{
Result: []*atlasexec.MigrateApply{
{Error: "sql/migrate: execution failed"},
},
}
require.Equal(t, "sql/migrate: execution failed", e.Error())
})
t.Run("stderr only", func(t *testing.T) {
e := &atlasexec.MigrateApplyError{
Stderr: "Error: unable to acquire lock",
}
require.Equal(t, "Error: unable to acquire lock", e.Error())
})
t.Run("single result error and stderr", func(t *testing.T) {
e := &atlasexec.MigrateApplyError{
Result: []*atlasexec.MigrateApply{
{Error: "sql/migrate: execution failed"},
},
Stderr: "Error: unable to acquire lock",
}
require.Equal(t, "sql/migrate: execution failed\nError: unable to acquire lock", e.Error())
})
t.Run("multiple result errors and stderr", func(t *testing.T) {
e := &atlasexec.MigrateApplyError{
Result: []*atlasexec.MigrateApply{
{Error: "error on target 1"},
{Error: "error on target 2"},
},
Stderr: "Error: unable to acquire lock",
}
require.Equal(t, "error on target 1\nerror on target 2\nError: unable to acquire lock", e.Error())
})
t.Run("multiple results with some having no error", func(t *testing.T) {
e := &atlasexec.MigrateApplyError{
Result: []*atlasexec.MigrateApply{
{Error: ""},
{Error: "error on target 2"},
{Error: ""},
},
Stderr: "Error: unable to acquire lock",
}
require.Equal(t, "error on target 2\nError: unable to acquire lock", e.Error())
})
t.Run("no errors at all", func(t *testing.T) {
e := &atlasexec.MigrateApplyError{
Result: []*atlasexec.MigrateApply{
{Error: ""},
},
}
require.Equal(t, "", e.Error())
})
t.Run("nil result with stderr", func(t *testing.T) {
e := &atlasexec.MigrateApplyError{
Stderr: "Error: connection refused",
}
require.Equal(t, "Error: connection refused", e.Error())
})
}
func TestAtlasMigrate_Apply(t *testing.T) {
ec, err := atlasexec.NewWorkingDir(
atlasexec.WithMigrations(os.DirFS(filepath.Join("testdata", "migrations"))),
atlasexec.WithAtlasHCL(func(w io.Writer) error {
_, err := w.Write([]byte(`
variable "url" {
type = string
default = getenv("DB_URL")
}
env {
name = atlas.env
url = var.url
migration {
dir = "file://migrations"
}
}`))
return err
}),
)
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, ec.Close())
})
c, err := atlasexec.NewClient(ec.Path(), "atlas")
require.NoError(t, err)
got, err := c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{
Env: "test",
})
require.ErrorContains(t, err, `required flag "url" not set`)
require.Nil(t, got)
var exerr *exec.ExitError
require.ErrorAs(t, err, &exerr)
// Set the env var and try again
os.Setenv("DB_URL", "sqlite://file?_fk=1&cache=shared&mode=memory")
got, err = c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{
Env: "test",
})
require.NoError(t, err)
require.Equal(t, "sqlite", got.Env.Driver)
require.Equal(t, "file://migrations", got.Env.Dir)
require.Equal(t, "sqlite://file?_fk=1&cache=shared&mode=memory", got.Env.URL.String())
require.Equal(t, "20230926085734", got.Target)
// Add dirty changes and try again
os.Setenv("DB_URL", "sqlite://test.db?_fk=1&cache=shared&mode=memory")
drv, err := sql.Open("sqlite3", "test.db")
require.NoError(t, err)
defer os.Remove("test.db")
_, err = drv.ExecContext(context.Background(), "create table atlas_schema_revisions(version varchar(255) not null primary key);")
require.NoError(t, err)
got, err = c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{
Env: "test",
AllowDirty: true,
})
require.NoError(t, err)
require.EqualValues(t, "20230926085734", got.Target)
}
func TestAtlasMigrate_ApplyWithRemote(t *testing.T) {
type (
ContextInput struct {
TriggerType string `json:"triggerType,omitempty"`
TriggerVersion string `json:"triggerVersion,omitempty"`
}
graphQLQuery struct {
Query string `json:"query"`
Variables json.RawMessage `json:"variables"`
MigrateApplyReport struct {
Input struct {
Context *ContextInput `json:"context,omitempty"`
} `json:"input"`
}
}
)
token := "123456789"
handler := func(payloads *[]graphQLQuery) http.HandlerFunc {
return func(_ http.ResponseWriter, r *http.Request) {
require.Equal(t, "Bearer "+token, r.Header.Get("Authorization"))
var query graphQLQuery
require.NoError(t, json.NewDecoder(r.Body).Decode(&query))
*payloads = append(*payloads, query)
}
}
var payloads []graphQLQuery
srv := httptest.NewServer(handler(&payloads))
t.Cleanup(srv.Close)
ec, err := atlasexec.NewWorkingDir(
atlasexec.WithMigrations(os.DirFS(filepath.Join("testdata", "migrations"))),
atlasexec.WithAtlasHCL(func(w io.Writer) error {
_, err := fmt.Fprintf(w, `
env {
name = atlas.env
url = "sqlite://file?_fk=1&cache=shared&mode=memory"
migration {
dir = "atlas://test_dir"
}
}
atlas {
cloud {
token = %q
url = %q
}
}`, token, srv.URL)
return err
}),
)
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, ec.Close())
})
c, err := atlasexec.NewClient(ec.Path(), "atlas")
require.NoError(t, err)
got, err := c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{
Env: "test",
})
require.NoError(t, err)
require.NotNil(t, got)
require.Len(t, payloads, 3)
reportPayload := payloads[2]
require.Regexp(t, "mutation ReportMigration", reportPayload.Query)
err = json.Unmarshal(reportPayload.Variables, &reportPayload.MigrateApplyReport)
require.NoError(t, err)
require.Nil(t, reportPayload.MigrateApplyReport.Input.Context)
got, err = c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{
Env: "test",
Context: &atlasexec.DeployRunContext{TriggerVersion: "1.2.3", TriggerType: atlasexec.TriggerTypeGithubAction},
})
require.NoError(t, err)
require.NotNil(t, got)
require.Len(t, payloads, 6)
reportPayload = payloads[5]
require.Regexp(t, "mutation ReportMigration", reportPayload.Query)
err = json.Unmarshal(reportPayload.Variables, &reportPayload.MigrateApplyReport)
require.NoError(t, err)
require.NotNil(t, reportPayload.MigrateApplyReport.Input.Context)
require.Equal(t, "GITHUB_ACTION", reportPayload.MigrateApplyReport.Input.Context.TriggerType)
require.Equal(t, "1.2.3", reportPayload.MigrateApplyReport.Input.Context.TriggerVersion)
}
func TestAtlasMigrate_Push(t *testing.T) {
type (
graphQLQuery struct {
Query string `json:"query"`
Variables json.RawMessage `json:"variables"`
PushDir *struct {
Input struct {
Slug string `json:"slug"`
Tag string `json:"tag"`
Driver string `json:"driver"`
Dir string `json:"dir"`
} `json:"input"`
}
DiffSyncDir *struct {
Input struct {
Slug string `json:"slug"`
Driver string `json:"driver"`
Dir string `json:"dir"`
Add string `json:"add"`
Delete []string `json:"delete"`
Context *atlasexec.RunContext `json:"context"`
} `json:"input"`
}
}
httpTest struct {
payloads []graphQLQuery
srv *httptest.Server
}
)
token := "123456789"
newHTTPTest := func() (*httpTest, string) {
tt := &httpTest{}
handler := func() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "Bearer "+token, r.Header.Get("Authorization"))
var query graphQLQuery
require.NoError(t, json.NewDecoder(r.Body).Decode(&query))
if strings.Contains(query.Query, "pushDir") {
err := json.Unmarshal(query.Variables, &query.PushDir)
require.NoError(t, err)
fmt.Fprint(w, `{"data":{"pushDir":{"url":"https://some-org.atlasgo.cloud/dirs/314159/tags/12345"}}}`)
}
if strings.Contains(query.Query, "diffSyncDir") {
err := json.Unmarshal(query.Variables, &query.DiffSyncDir)
require.NoError(t, err)
fmt.Fprint(w, `{"data":{"diffSyncDir":{"url":"https://some-org.atlasgo.cloud/dirs/314159/tags/12345"}}}`)
}
tt.payloads = append(tt.payloads, query)
}
}
tt.srv = httptest.NewServer(handler())
t.Cleanup(tt.srv.Close)
return tt, generateHCL(t, token, tt.srv)
}
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
inputContext := &atlasexec.RunContext{
Repo: "testing-repo",
Path: "path/to/dir",
Branch: "testing-branch",
Commit: "sha123",
URL: "this://is/a/url",
UserID: "test-user-id",
Username: "test-user",
SCMType: atlasexec.SCMTypeGithub,
}
t.Run("sync", func(t *testing.T) {
params := &atlasexec.MigratePushParams{
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
Name: "test-dir-slug",
Env: "test",
}
t.Run("with context", func(t *testing.T) {
tt, atlasConfigURL := newHTTPTest()
params.ConfigURL = atlasConfigURL
got, err := c.MigratePush(context.Background(), params)
require.NoError(t, err)
require.Len(t, tt.payloads, 3)
require.Equal(t, `https://some-org.atlasgo.cloud/dirs/314159/tags/12345`, got)
p := &tt.payloads[2]
require.Contains(t, p.Query, "diffSyncDir")
require.Equal(t, "test-dir-slug", p.DiffSyncDir.Input.Slug)
require.Equal(t, "SQLITE", p.DiffSyncDir.Input.Driver)
require.NotEmpty(t, p.DiffSyncDir.Input.Dir)
})
t.Run("without context", func(t *testing.T) {
tt, atlasConfigURL := newHTTPTest()
params.ConfigURL = atlasConfigURL
params.Context = inputContext
got, err := c.MigratePush(context.Background(), params)
require.NoError(t, err)
require.Equal(t, `https://some-org.atlasgo.cloud/dirs/314159/tags/12345`, got)
require.Len(t, tt.payloads, 3)
p := &tt.payloads[2]
require.Contains(t, p.Query, "diffSyncDir")
err = json.Unmarshal(p.Variables, &p.DiffSyncDir)
require.NoError(t, err)
require.Equal(t, inputContext, p.DiffSyncDir.Input.Context)
})
})
t.Run("push", func(t *testing.T) {
tt, atlasConfigURL := newHTTPTest()
params := &atlasexec.MigratePushParams{
ConfigURL: atlasConfigURL,
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
Name: "test-dir-slug",
Context: inputContext,
Env: "test",
Tag: "this-is-my-tag",
}
got, err := c.MigratePush(context.Background(), params)
require.NoError(t, err)
require.Equal(t, `https://some-org.atlasgo.cloud/dirs/314159/tags/12345`, got)
require.Len(t, tt.payloads, 2)
p := &tt.payloads[1]
require.Contains(t, p.Query, "pushDir")
require.Equal(t, "test-dir-slug", p.PushDir.Input.Slug)
require.Equal(t, "SQLITE", p.PushDir.Input.Driver)
require.Equal(t, "this-is-my-tag", p.PushDir.Input.Tag)
require.NotEmpty(t, p.PushDir.Input.Dir)
})
}
func TestMigrateHash(t *testing.T) {
td := t.TempDir()
require.NoError(t, os.Mkdir(fmt.Sprintf("%s/migrations", td), 0777))
require.NoError(t, os.WriteFile(fmt.Sprintf("%s/migrations/1.sql", td), []byte(`create table t (c int not null)`), 0666))
c, err := atlasexec.NewClient(td, "atlas")
require.NoError(t, err)
inspect := func() error {
_, err = c.SchemaInspect(context.Background(), &atlasexec.SchemaInspectParams{
DevURL: "sqlite://file?mode=memory",
URL: fmt.Sprintf("file://%s/migrations", td),
})
return err
}
require.ErrorContains(t, inspect(), "checksum file not found")
require.NoError(t, c.MigrateHash(context.Background(), &atlasexec.MigrateHashParams{}))
require.FileExists(t, fmt.Sprintf("%s/migrations/atlas.sum", td))
require.NoError(t, inspect())
}
func TestMigrateRebase(t *testing.T) {
td := t.TempDir()
require.NoError(t, os.Mkdir(fmt.Sprintf("%s/migrations", td), 0777))
// create initial migrations dir state
require.NoError(t, os.WriteFile(fmt.Sprintf("%s/migrations/2024030709.sql", td), []byte(`create table t (c int not null)`), 0666))
require.NoError(t, os.WriteFile(fmt.Sprintf("%s/migrations/2024030711.sql", td), []byte("alter table `t` add column `c3` text not null;"), 0666))
c, err := atlasexec.NewClient(td, "atlas")
require.NoError(t, err)
require.NoError(t, c.MigrateHash(context.Background(), &atlasexec.MigrateHashParams{}))
require.FileExists(t, fmt.Sprintf("%s/migrations/atlas.sum", td))
// Print atlas.sum before adding a new migration
before, err := os.ReadFile(fmt.Sprintf("%s/migrations/atlas.sum", td))
require.NoError(t, err)
// add a new migration
require.NoError(t, os.WriteFile(fmt.Sprintf("%s/migrations/2024030710.sql", td), []byte("alter table `t` add column `c2` text not null;"), 0666))
require.NoError(t, c.MigrateHash(context.Background(), &atlasexec.MigrateHashParams{}))
require.FileExists(t, fmt.Sprintf("%s/migrations/atlas.sum", td))
require.NoError(t, c.MigrateRebase(context.Background(), &atlasexec.MigrateRebaseParams{
Files: []string{
"2024030711.sql",
},
DirURL: fmt.Sprintf("file://%s/migrations", td),
}))
inspect := func() error {
_, err = c.SchemaInspect(context.Background(), &atlasexec.SchemaInspectParams{
DevURL: "sqlite://file?mode=memory",
URL: fmt.Sprintf("file://%s/migrations", td),
})
return err
}
// ensure sum file changes after rebase
after, err := os.ReadFile(fmt.Sprintf("%s/migrations/atlas.sum", td))
require.NotEqual(t, before, after)
require.NoError(t, inspect())
}
func TestAtlasMigrate_Lint(t *testing.T) {
t.Run("with broken config", func(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
got, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{
ConfigURL: "file://config-broken.hcl",
})
require.ErrorContains(t, err, `file "config-broken.hcl" was not found`)
require.Nil(t, got)
})
t.Run("with broken dev-url", func(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
got, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{
DirURL: "file://atlasexec/testdata/migrations",
})
require.ErrorContains(t, err, `required flag(s) "dev-url" not set`)
require.Nil(t, got)
})
t.Run("broken dir", func(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
got, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{
DevURL: "sqlite://file?mode=memory",
DirURL: "file://atlasexec/testdata/doesnotexist",
})
require.ErrorContains(t, err, `stat atlasexec/testdata/doesnotexist: no such file or directory`)
require.Nil(t, got)
})
t.Run("lint error parsing", func(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
got, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
Latest: 1,
})
require.NoError(t, err)
require.GreaterOrEqual(t, 4, len(got.Steps))
require.Equal(t, "sqlite", got.Env.Driver)
require.Equal(t, "testdata/migrations", got.Env.Dir)
require.Equal(t, "sqlite://file?mode=memory", got.Env.URL.String())
require.Equal(t, 1, len(got.Files))
expectedReport := &atlasexec.FileReport{
Name: "20230926085734_destructive-change.sql",
Text: "DROP TABLE t2;\n",
Reports: []sqlcheck.Report{{
Text: "destructive changes detected",
Diagnostics: []sqlcheck.Diagnostic{{
Pos: 0,
Text: `Dropping table "t2"`,
Code: "DS102",
SuggestedFixes: []sqlcheck.SuggestedFix{{
Message: "Add a pre-migration check to ensure table \"t2\" is empty before dropping it",
TextEdit: &sqlcheck.TextEdit{
Line: 1,
End: 1,
NewText: "-- atlas:txtar\n\n-- checks/destructive.sql --\n-- atlas:assert DS102\nSELECT NOT EXISTS (SELECT 1 FROM `t2`) AS `is_empty`;\n\n-- migration.sql --\nDROP TABLE t2;",
},
}},
}},
}},
Error: "destructive changes detected",
}
require.EqualValues(t, expectedReport, got.Files[0])
})
t.Run("lint with manually parsing output", func(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
var buf bytes.Buffer
err = c.MigrateLintError(context.Background(), &atlasexec.MigrateLintParams{
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
Latest: 1,
Writer: &buf,
})
require.Equal(t, atlasexec.ErrLint, err)
var raw json.RawMessage
require.NoError(t, json.NewDecoder(&buf).Decode(&raw))
require.Contains(t, string(raw), "destructive changes detected")
})
t.Run("lint uses --base and --latest", func(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
summary, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
Latest: 1,
Base: "atlas://test-dir",
})
require.ErrorContains(t, err, "--latest, --git-base, and --base are mutually exclusive")
require.Nil(t, summary)
})
}
func TestAtlasMigrate_LintWithLogin(t *testing.T) {
type (
migrateLintReport struct {
Context *atlasexec.RunContext `json:"context"`
}
graphQLQuery struct {
Query string `json:"query"`
Variables json.RawMessage `json:"variables"`
MigrateLintReport struct {
migrateLintReport `json:"input"`
}
}
Dir struct {
Name string `json:"name"`
Content string `json:"content"`
Slug string `json:"slug"`
}
dirsQueryResponse struct {
Data struct {
Dirs []Dir `json:"dirs"`
} `json:"data"`
}
)
token := "123456789"
handler := func(payloads *[]graphQLQuery) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "Bearer "+token, r.Header.Get("Authorization"))
var query graphQLQuery
require.NoError(t, json.NewDecoder(r.Body).Decode(&query))
*payloads = append(*payloads, query)
switch {
case strings.Contains(query.Query, "mutation reportMigrationLint"):
_, err := fmt.Fprintf(w, `{ "data": { "reportMigrationLint": { "url": "https://migration-lint-report-url" } } }`)
require.NoError(t, err)
case strings.Contains(query.Query, "query dirs"):
dir, err := migrate.NewLocalDir("./testdata/migrations")
require.NoError(t, err)
ad, err := migrate.ArchiveDir(dir)
require.NoError(t, err)
var resp dirsQueryResponse
resp.Data.Dirs = []Dir{{
Name: "test-dir-name",
Slug: "test-dir-slug",
Content: base64.StdEncoding.EncodeToString(ad),
}}
st2bytes, err := json.Marshal(resp)
require.NoError(t, err)
_, err = fmt.Fprint(w, string(st2bytes))
require.NoError(t, err)
}
}
}
t.Run("Web and Writer params produces an error", func(t *testing.T) {
var payloads []graphQLQuery
srv := httptest.NewServer(handler(&payloads))
t.Cleanup(srv.Close)
atlasConfigURL := generateHCL(t, token, srv)
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
params := &atlasexec.MigrateLintParams{
ConfigURL: atlasConfigURL,
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
Latest: 1,
Web: true,
}
got, err := c.MigrateLint(context.Background(), params)
require.ErrorContains(t, err, "Writer or Web reporting are not supported")
require.Nil(t, got)
params.Web = false
params.Writer = &bytes.Buffer{}
got, err = c.MigrateLint(context.Background(), params)
require.ErrorContains(t, err, "Writer or Web reporting are not supported")
require.Nil(t, got)
})
t.Run("lint parse web output - no error - custom format", func(t *testing.T) {
var payloads []graphQLQuery
srv := httptest.NewServer(handler(&payloads))
t.Cleanup(srv.Close)
atlasConfigURL := generateHCL(t, token, srv)
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
var buf bytes.Buffer
err = c.MigrateLintError(context.Background(), &atlasexec.MigrateLintParams{
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
ConfigURL: atlasConfigURL,
Latest: 1,
Writer: &buf,
Format: "{{ .URL }}",
Web: true,
})
require.Equal(t, err, atlasexec.ErrLint)
require.Equal(t, strings.TrimSpace(buf.String()), "https://migration-lint-report-url")
})
t.Run("lint parse web output - no error - default format", func(t *testing.T) {
var payloads []graphQLQuery
srv := httptest.NewServer(handler(&payloads))
t.Cleanup(srv.Close)
atlasConfigURL := generateHCL(t, token, srv)
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
var buf bytes.Buffer
err = c.MigrateLintError(context.Background(), &atlasexec.MigrateLintParams{
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
ConfigURL: atlasConfigURL,
Latest: 1,
Writer: &buf,
Web: true,
})
require.Equal(t, atlasexec.ErrLint, err)
var sr atlasexec.SummaryReport
require.NoError(t, json.NewDecoder(&buf).Decode(&sr))
require.Equal(t, "https://migration-lint-report-url", sr.URL)
})
t.Run("lint uses --base", func(t *testing.T) {
var payloads []graphQLQuery
srv := httptest.NewServer(handler(&payloads))
t.Cleanup(srv.Close)
atlasConfigURL := generateHCL(t, token, srv)
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
summary, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
ConfigURL: atlasConfigURL,
Base: "atlas://test-dir-slug",
})
require.NoError(t, err)
require.NotNil(t, summary)
})
t.Run("lint uses --context has error", func(t *testing.T) {
var payloads []graphQLQuery
srv := httptest.NewServer(handler(&payloads))
t.Cleanup(srv.Close)
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
var (
buf bytes.Buffer
atlasConfigURL = generateHCL(t, token, srv)
runContext = &atlasexec.RunContext{
Repo: "testing-repo",
Path: "path/to/dir",
Branch: "testing-branch",
Commit: "sha123",
URL: "this://is/a/url",
Username: "test-user",
UserID: "test-user-id",
SCMType: atlasexec.SCMTypeGithub,
}
)
err = c.MigrateLintError(context.Background(), &atlasexec.MigrateLintParams{
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
ConfigURL: atlasConfigURL,
Base: "atlas://test-dir-slug",
Context: runContext,
Writer: &buf,
Web: true,
})
require.Equal(t, atlasexec.ErrLint, err)
var sr atlasexec.SummaryReport
require.NoError(t, json.NewDecoder(&buf).Decode(&sr))
require.Equal(t, "https://migration-lint-report-url", sr.URL)
found := false
for _, query := range payloads {
if !strings.Contains(query.Query, "mutation reportMigrationLint") {
continue
}
found = true
require.NoError(t, json.Unmarshal(query.Variables, &query.MigrateLintReport))
require.Equal(t, runContext, query.MigrateLintReport.Context)
}
require.True(t, found)
})
}
func TestMigrate_Diff(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
td := t.TempDir()
require.NoError(t, os.WriteFile(fmt.Sprintf("%s/schema.sql", td), []byte(`create table t (c int not null)`), 0666))
params := &atlasexec.MigrateDiffParams{
ToURL: fmt.Sprintf("file://%s/schema.sql", td),
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
Name: "test-diff",
}
output, err := c.MigrateDiff(context.Background(), params)
require.NoError(t, err)
require.Len(t, output.Files, 1)
require.Contains(t, output.Files[0].Name, "test-diff.sql")
require.Equal(t, output.Files[0].Content, "-- Disable the enforcement of foreign-keys constraints\nPRAGMA foreign_keys = off;\n-- Drop \"t1\" table\nDROP TABLE `t1`;\n-- Create \"t\" table\nCREATE TABLE `t` (\n `c` int NOT NULL\n);\n-- Enable back the enforcement of foreign-keys constraints\nPRAGMA foreign_keys = on;\n")
require.Equal(t, output.Dir, "file://testdata/migrations?format=atlas")
// No diff
params = &atlasexec.MigrateDiffParams{
ToURL: "file://testdata/migrations",
DevURL: "sqlite://file?mode=memory",
DirURL: "file://testdata/migrations",
Name: "test-diff",
}
output, err = c.MigrateDiff(context.Background(), params)
require.NoError(t, err)
require.Len(t, output.Files, 0)
}
================================================
FILE: atlasexec/atlas_models.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec
import (
"errors"
"time"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlcheck"
"ariga.io/atlas/sql/sqlclient"
)
type (
// File wraps migrate.File to implement json.Marshaler.
File struct {
Name string `json:"Name,omitempty"`
Version string `json:"Version,omitempty"`
Description string `json:"Description,omitempty"`
Content string `json:"Content,omitempty"`
}
// AppliedFile is part of a MigrateApply containing information about an applied file in a migration attempt.
AppliedFile struct {
File
Start time.Time
End time.Time
Skipped int // Amount of skipped SQL statements in a partially applied file.
Applied []string // SQL statements applied with success
Checks []*FileChecks // Assertion checks
Error *struct {
Stmt string // SQL statement that failed.
Text string // Error returned by the database.
}
}
// RevertedFile is part of a MigrateDown containing information about a reverted file in a downgrade attempt.
RevertedFile struct {
File
Start time.Time
End time.Time
Skipped int // Amount of skipped SQL statements in a partially applied file.
Applied []string // SQL statements applied with success
Scope string // Scope of the revert. e.g., statement, versions, etc.
Error *struct {
Stmt string // SQL statement that failed.
Text string // Error returned by the database.
}
}
// A SummaryReport contains a summary of the analysis of all files.
// It is used as an input to templates to report the CI results.
SummaryReport struct {
URL string `json:"URL,omitempty"` // URL of the report, if exists.
// Env holds the environment information.
Env struct {
Driver string `json:"Driver,omitempty"` // Driver name.
URL *sqlclient.URL `json:"URL,omitempty"` // URL to dev database.
Dir string `json:"Dir,omitempty"` // Path to migration directory.
}
// Schema versions found by the runner.
Schema struct {
Current string `json:"Current,omitempty"` // Current schema.
Desired string `json:"Desired,omitempty"` // Desired schema.
}
// Steps of the analysis. Added in verbose mode.
Steps []*StepReport `json:"Steps,omitempty"`
// Files reports. Non-empty in case there are findings.
Files []*FileReport `json:"Files,omitempty"`
}
// StepReport contains a summary of the analysis of a single step.
StepReport struct {
Name string `json:"Name,omitempty"` // Step name.
Text string `json:"Text,omitempty"` // Step description.
Error string `json:"Error,omitempty"` // Error that cause the execution to halt.
Result *FileReport `json:"Result,omitempty"` // Result of the step. For example, a diagnostic.
}
// FileReport contains a summary of the analysis of a single file.
FileReport struct {
Name string `json:"Name,omitempty"` // Name of the file.
Text string `json:"Text,omitempty"` // Contents of the file.
Reports []sqlcheck.Report `json:"Reports,omitempty"` // List of reports.
Error string `json:"Error,omitempty"` // File specific error.
}
// FileChecks represents a set of checks to run before applying a file.
FileChecks struct {
Name string `json:"Name,omitempty"` // File/group name.
Stmts []*Check `json:"Stmts,omitempty"` // Checks statements executed.
Error *StmtError `json:"Error,omitempty"` // Assertion error.
Start time.Time `json:"Start,omitempty"` // Start assertion time.
End time.Time `json:"End,omitempty"` // End assertion time.
}
// Check represents an assertion and its status.
Check struct {
Stmt string `json:"Stmt,omitempty"` // Assertion statement.
Error *string `json:"Error,omitempty"` // Assertion error, if any.
}
// StmtError groups a statement with its execution error.
StmtError struct {
Stmt string `json:"Stmt,omitempty"` // SQL statement that failed.
Text string `json:"Text,omitempty"` // Error message as returned by the database.
}
// Env holds the environment information.
Env struct {
Driver string `json:"Driver,omitempty"` // Driver name.
URL *sqlclient.URL `json:"URL,omitempty"` // URL to dev database.
Dir string `json:"Dir,omitempty"` // Path to migration directory.
}
// Changes represents a list of changes that are pending or applied.
Changes struct {
Applied []string `json:"Applied,omitempty"` // SQL changes applied with success
Pending []string `json:"Pending,omitempty"` // SQL changes that were not applied
Error *StmtError `json:"Error,omitempty"` // Error that occurred during applying
}
// A Revision denotes an applied migration in a deployment. Used to track migration executions state of a database.
Revision struct {
Version string `json:"Version"` // Version of the migration.
Description string `json:"Description"` // Description of this migration.
Type string `json:"Type"` // Type of the migration.
Applied int `json:"Applied"` // Applied amount of statements in the migration.
Total int `json:"Total"` // Total amount of statements in the migration.
ExecutedAt time.Time `json:"ExecutedAt"` // ExecutedAt is the starting point of execution.
ExecutionTime time.Duration `json:"ExecutionTime"` // ExecutionTime of the migration.
Error string `json:"Error,omitempty"` // Error of the migration, if any occurred.
ErrorStmt string `json:"ErrorStmt,omitempty"` // ErrorStmt is the statement that raised Error.
OperatorVersion string `json:"OperatorVersion"` // OperatorVersion that executed this migration.
}
// A Report describes a schema analysis report with an optional specific diagnostic.
Report struct {
Text string `json:"Text"` // Report text.
Desc string `json:"Desc,omitempty"` // Optional description (secondary text).
Error bool `json:"Error,omitempty"` // Report is an error report.
Diagnostics []Diagnostic `json:"Diagnostics,omitempty"` // Report diagnostics.
}
// A Diagnostic is a text associated with a specific position of a definition/element in a file.
Diagnostic struct {
Pos *schema.Pos `json:"Pos,omitempty"` // Element position.
Text string `json:"Text"` // Diagnostic text.
Code string `json:"Code,omitempty"` // Code describes the check (optional).
}
// TableSizeMetric represents a table size metric from schema stats
TableSizeMetric struct {
Schema string `json:"schema"`
Table string `json:"table"`
Value float64 `json:"value"`
}
)
// MetricTableSizeBytes is the name of the table size metric in bytes.
const MetricTableSizeBytes = "atlas_table_size_bytes"
// DiagnosticsCount returns the total number of diagnostics in the report.
func (r *SummaryReport) DiagnosticsCount() int {
var n int
for _, f := range r.Files {
for _, r := range f.Reports {
n += len(r.Diagnostics)
}
}
return n
}
// Errors returns the errors in the summary report, if exists.
func (r *SummaryReport) Errors() []error {
var errs []error
for _, f := range r.Files {
if f.Error != "" {
errs = append(errs, errors.New(f.Error))
}
}
return errs
}
================================================
FILE: atlasexec/atlas_schema.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec
import (
"context"
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"ariga.io/atlas/sql/migrate"
)
type (
// SchemaPushParams are the parameters for the `schema push` command.
SchemaPushParams struct {
ConfigURL string
Env string
Vars VarArgs
Context *RunContext
DevURL string
URL []string // Desired schema URL(s) to push
Schema []string // If set, only the specified schemas are pushed.
Name string // Name of the schema (repo) to push to.
Tag string // Tag to push the schema with
Version string // Version of the schema to push. Defaults to the current timestamp.
Description string // Description of the schema changes.
}
// SchemaPush represents the result of a 'schema push' command.
SchemaPush struct {
Link string
Slug string
URL string
}
// SchemaApplyParams are the parameters for the `schema apply` command.
SchemaApplyParams struct {
ConfigURL string
Env string
Vars VarArgs
DevURL string
URL string
To string // TODO: change to []string
TxMode string
Exclude []string
Include []string
Schema []string
DryRun bool // If true, --dry-run is set.
AutoApprove bool // If true, --auto-approve is set.
PlanURL string // URL of the plan in Atlas format (atlas:///plans/). (optional)
LockName string
}
// SchemaApply represents the result of a 'schema apply' command.
SchemaApply struct {
Env
// Changes holds the changes applied to the database.
// Exists for backward compatibility with the old schema
// apply structure as old SDK versions rely on it.
Changes Changes `json:"Changes,omitempty"`
Error string `json:"Error,omitempty"` // Any error that occurred during execution.
Start time.Time `json:"Start,omitempty"` // When apply (including plan) started.
End time.Time `json:"End,omitempty"` // When apply ended.
Applied *AppliedFile `json:"Applied,omitempty"` // Applied migration file (pre-planned or computed).
// Plan information might be partially filled. For example, if lint is done
// during plan-stage, the linting report is available in the Plan field. If
// the migration is pre-planned migration, the File.URL is set, etc.
Plan *SchemaPlan `json:"Plan,omitempty"`
}
// SchemaApplyError is returned when an error occurred
// during a schema applying attempt.
SchemaApplyError struct {
Result []*SchemaApply
Stderr string
}
// SchemaInspectParams are the parameters for the `schema inspect` command.
SchemaInspectParams struct {
ConfigURL string
Env string
Vars VarArgs
Format string
DevURL string
URL string
Exclude []string
Include []string
Schema []string
}
// SchemaTestParams are the parameters for the `schema test` command.
SchemaTestParams struct {
ConfigURL string
Env string
Vars VarArgs
DevURL string
URL string
Run string
Paths []string
}
// SchemaPlanParams are the parameters for the `schema plan` command.
SchemaPlanParams struct {
ConfigURL string
Env string
Vars VarArgs
Context *RunContext
DevURL string
Exclude []string
Include []string
Schema []string
From, To []string
Repo string
Name string
Directives []string
// The below are mutually exclusive and can be replaced
// with the 'schema plan' sub-commands instead.
DryRun bool // If false, --auto-approve is set.
Pending bool
Push, Save bool
}
// SchemaPlanListParams are the parameters for the `schema plan list` command.
SchemaPlanListParams struct {
ConfigURL string
Env string
Vars VarArgs
Context *RunContext
DevURL string
Schema []string
Exclude []string
Include []string
From, To []string
Repo string
Pending bool // If true, only pending plans are listed.
}
// SchemaPlanPushParams are the parameters for the `schema plan push` command.
SchemaPlanPushParams struct {
ConfigURL string
Env string
Vars VarArgs
Context *RunContext
DevURL string
Schema []string
Exclude []string
Include []string
From, To []string
Repo string
Pending bool // Push plan in pending state.
File string // File to push. (optional)
}
// SchemaPlanPullParams are the parameters for the `schema plan pull` command.
SchemaPlanPullParams struct {
ConfigURL string
Env string
Vars VarArgs
URL string // URL to the plan in Atlas format. (required)
}
// SchemaPlanLintParams are the parameters for the `schema plan lint` command.
SchemaPlanLintParams struct {
ConfigURL string
Env string
Vars VarArgs
Context *RunContext
DevURL string
Schema []string
Exclude []string
Include []string
From, To []string
Repo string
File string
}
// SchemaPlanValidateParams are the parameters for the `schema plan validate` command.
SchemaPlanValidateParams struct {
ConfigURL string
Env string
Vars VarArgs
Context *RunContext
DevURL string
Schema []string
Exclude []string
Include []string
From, To []string
Repo string
Name string
File string
}
// SchemaPlanApproveParams are the parameters for the `schema plan approve` command.
SchemaPlanApproveParams struct {
ConfigURL string
Env string
Vars VarArgs
URL string
}
// SchemaPlan is the result of a 'schema plan' command.
SchemaPlan struct {
Env Env `json:"Env,omitempty"` // Environment info.
Repo string `json:"Repo,omitempty"` // Repository name.
Lint *SummaryReport `json:"Lint,omitempty"` // Lint report.
File *SchemaPlanFile `json:"File,omitempty"` // Plan file.
Error string `json:"Error,omitempty"` // Any error occurred during planning.
}
// SchemaPlanApprove is the result of a 'schema plan approve' command.
SchemaPlanApprove struct {
URL string `json:"URL,omitempty"` // URL of the plan in Atlas format.
Link string `json:"Link,omitempty"` // Link to the plan in the registry.
Status string `json:"Status,omitempty"` // Status of the plan in the registry.
}
// SchemaPlanFile is a JSON representation of a schema plan file.
SchemaPlanFile struct {
Name string `json:"Name,omitempty"` // Name of the plan.
FromHash string `json:"FromHash,omitempty"` // Hash of the 'from' realm.
FromDesc string `json:"FromDesc,omitempty"` // Optional description of the 'from' state.
ToHash string `json:"ToHash,omitempty"` // Hash of the 'to' realm.
ToDesc string `json:"ToDesc,omitempty"` // Optional description of the 'to' state.
Migration string `json:"Migration,omitempty"` // Migration SQL.
Stmts []*migrate.Stmt `json:"Stmts,omitempty"` // Statements in the migration (available only in the JSON output).
// registry only fields.
URL string `json:"URL,omitempty"` // URL of the plan in Atlas format.
Link string `json:"Link,omitempty"` // Link to the plan in the registry.
Status string `json:"Status,omitempty"` // Status of the plan in the registry.
}
// SchemaCleanParams are the parameters for the `schema clean` command.
SchemaCleanParams struct {
ConfigURL string
Env string
Vars VarArgs
URL string // URL of the schema to clean. (required)
DryRun bool // If true, --dry-run is set.
AutoApprove bool // If true, --auto-approve is set.
}
// SchemaClean represents the result of a 'schema clean' command.
SchemaClean struct {
Env
Start time.Time `json:"Start,omitempty"` // When clean started.
End time.Time `json:"End,omitempty"` // When clean ended.
Applied *AppliedFile `json:"Applied,omitempty"` // Applied migration file.
Error string `json:"Error,omitempty"` // Any error that occurred during execution.
}
// SchemaLintParams are the parameters for the `schema lint` command.
SchemaLintParams struct {
ConfigURL string
Env string
Vars VarArgs
URL []string // Schema URL(s) to lint
Schema []string // If set, only the specified schemas are linted.
Format string
DevURL string
}
// SchemaLintReport holds the results of a schema lint operation
SchemaLintReport struct {
Steps []Report `json:"Steps,omitempty"`
}
// SchemaStatsInspectParams are the parameters for the `schema stat inspect` command.
SchemaStatsInspectParams struct {
ConfigURL string
Env string
Vars VarArgs
URL string
Exclude []string
Include []string
Schema []string
}
)
// SchemaPush runs the 'schema push' command.
func (c *Client) SchemaPush(ctx context.Context, params *SchemaPushParams) (*SchemaPush, error) {
args := []string{"schema", "push", "--format", "{{ json . }}"}
// Global flags
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
// Hidden flags
if params.Context != nil {
buf, err := json.Marshal(params.Context)
if err != nil {
return nil, err
}
args = append(args, "--context", string(buf))
}
// Flags of the 'schema push' sub-commands
args = append(args, repeatFlag("--url", params.URL)...)
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if len(params.Schema) > 0 {
args = append(args, "--schema", listString(params.Schema))
}
if params.Tag != "" {
args = append(args, "--tag", params.Tag)
}
if params.Version != "" {
args = append(args, "--version", params.Version)
}
if params.Description != "" {
args = append(args, "--desc", params.Description)
}
if params.Name != "" {
args = append(args, params.Name)
}
return firstResult(jsonDecode[SchemaPush](c.runCommand(ctx, args)))
}
// SchemaApply runs the 'schema apply' command.
func (c *Client) SchemaApply(ctx context.Context, params *SchemaApplyParams) (*SchemaApply, error) {
return firstResult(c.SchemaApplySlice(ctx, params))
}
// SchemaApplySlice runs the 'schema apply' command for multiple targets.
func (c *Client) SchemaApplySlice(ctx context.Context, params *SchemaApplyParams) ([]*SchemaApply, error) {
args := []string{"schema", "apply", "--format", "{{ json . }}"}
// Global flags
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
// Flags of the 'schema apply' sub-commands
if params.URL != "" {
args = append(args, "--url", params.URL)
}
if params.To != "" {
args = append(args, "--to", params.To)
}
if params.TxMode != "" {
args = append(args, "--tx-mode", params.TxMode)
}
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if len(params.Schema) > 0 {
args = append(args, "--schema", listString(params.Schema))
}
if len(params.Exclude) > 0 {
args = append(args, "--exclude", listString(params.Exclude))
}
if len(params.Include) > 0 {
args = append(args, "--include", listString(params.Include))
}
if params.PlanURL != "" {
args = append(args, "--plan", params.PlanURL)
}
if params.LockName != "" {
args = append(args, "--lock-name", params.LockName)
}
switch {
case params.DryRun:
args = append(args, "--dry-run")
case params.AutoApprove:
args = append(args, "--auto-approve")
}
return jsonDecodeErr(newSchemaApplyError)(c.runCommand(ctx, args))
}
// SchemaInspect runs the 'schema inspect' command.
func (c *Client) SchemaInspect(ctx context.Context, params *SchemaInspectParams) (string, error) {
args := []string{"schema", "inspect"}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.URL != "" {
args = append(args, "--url", params.URL)
}
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
switch {
case params.Format == "sql":
args = append(args, "--format", "{{ sql . }}")
case params.Format != "":
args = append(args, "--format", params.Format)
}
if len(params.Schema) > 0 {
args = append(args, "--schema", listString(params.Schema))
}
if len(params.Exclude) > 0 {
args = append(args, "--exclude", listString(params.Exclude))
}
if len(params.Include) > 0 {
args = append(args, "--include", listString(params.Include))
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
return stringVal(c.runCommand(ctx, args))
}
// SchemaTest runs the 'schema test' command.
func (c *Client) SchemaTest(ctx context.Context, params *SchemaTestParams) (string, error) {
args := []string{"schema", "test"}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.URL != "" {
args = append(args, "--url", params.URL)
}
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if params.Run != "" {
args = append(args, "--run", params.Run)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
if len(params.Paths) > 0 {
args = append(args, params.Paths...)
}
return stringVal(c.runCommand(ctx, args))
}
// SchemaPlan runs the `schema plan` command.
func (c *Client) SchemaPlan(ctx context.Context, params *SchemaPlanParams) (*SchemaPlan, error) {
args := []string{"schema", "plan", "--format", "{{ json . }}"}
// Global flags
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
// Hidden flags
if params.Context != nil {
buf, err := json.Marshal(params.Context)
if err != nil {
return nil, err
}
args = append(args, "--context", string(buf))
}
// Flags of the 'schema plan' sub-commands
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if len(params.Schema) > 0 {
args = append(args, "--schema", listString(params.Schema))
}
if len(params.Exclude) > 0 {
args = append(args, "--exclude", listString(params.Exclude))
}
if len(params.Include) > 0 {
args = append(args, "--include", listString(params.Include))
}
if len(params.From) > 0 {
args = append(args, "--from", listString(params.From))
}
if len(params.To) > 0 {
args = append(args, "--to", listString(params.To))
}
if params.Name != "" {
args = append(args, "--name", params.Name)
}
if params.Repo != "" {
args = append(args, "--repo", params.Repo)
}
if params.Save {
args = append(args, "--save")
}
if params.Push {
args = append(args, "--push")
}
if params.Pending {
args = append(args, "--pending")
}
if params.DryRun {
args = append(args, "--dry-run")
} else {
args = append(args, "--auto-approve")
}
for _, d := range params.Directives {
args = append(args, "--directive", strconv.Quote(d))
}
// NOTE: This command only support one result.
return firstResult(jsonDecode[SchemaPlan](c.runCommand(ctx, args)))
}
// SchemaPlanList runs the `schema plan list` command.
func (c *Client) SchemaPlanList(ctx context.Context, params *SchemaPlanListParams) ([]SchemaPlanFile, error) {
args := []string{"schema", "plan", "list", "--format", "{{ json . }}"}
// Global flags
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
// Hidden flags
if params.Context != nil {
buf, err := json.Marshal(params.Context)
if err != nil {
return nil, err
}
args = append(args, "--context", string(buf))
}
// Flags of the 'schema plan lint' sub-commands
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if len(params.Schema) > 0 {
args = append(args, "--schema", listString(params.Schema))
}
if len(params.Exclude) > 0 {
args = append(args, "--exclude", listString(params.Exclude))
}
if len(params.Include) > 0 {
args = append(args, "--include", listString(params.Include))
}
if len(params.From) > 0 {
args = append(args, "--from", listString(params.From))
}
if len(params.To) > 0 {
args = append(args, "--to", listString(params.To))
}
if params.Repo != "" {
args = append(args, "--repo", params.Repo)
}
if params.Pending {
args = append(args, "--pending")
}
args = append(args, "--auto-approve")
// NOTE: This command only support one result.
v, err := firstResult(jsonDecode[[]SchemaPlanFile](c.runCommand(ctx, args)))
if err != nil {
return nil, err
}
return *v, nil
}
// SchemaPlanPush runs the `schema plan push` command.
func (c *Client) SchemaPlanPush(ctx context.Context, params *SchemaPlanPushParams) (string, error) {
args := []string{"schema", "plan", "push", "--format", "{{ json . }}"}
// Global flags
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
// Hidden flags
if params.Context != nil {
buf, err := json.Marshal(params.Context)
if err != nil {
return "", err
}
args = append(args, "--context", string(buf))
}
// Flags of the 'schema plan push' sub-commands
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if len(params.Schema) > 0 {
args = append(args, "--schema", listString(params.Schema))
}
if len(params.Exclude) > 0 {
args = append(args, "--exclude", listString(params.Exclude))
}
if len(params.Include) > 0 {
args = append(args, "--include", listString(params.Include))
}
if len(params.From) > 0 {
args = append(args, "--from", listString(params.From))
}
if len(params.To) > 0 {
args = append(args, "--to", listString(params.To))
}
if params.File != "" {
args = append(args, "--file", params.File)
} else {
return "", &InvalidParamsError{"schema plan push", "missing required flag --file"}
}
if params.Repo != "" {
args = append(args, "--repo", params.Repo)
}
if params.Pending {
args = append(args, "--pending")
} else {
args = append(args, "--auto-approve")
}
return stringVal(c.runCommand(ctx, args))
}
// SchemaPlanPush runs the `schema plan pull` command.
func (c *Client) SchemaPlanPull(ctx context.Context, params *SchemaPlanPullParams) (string, error) {
args := []string{"schema", "plan", "pull"}
// Global flags
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
// Flags of the 'schema plan pull' sub-commands
if params.URL != "" {
args = append(args, "--url", params.URL)
} else {
return "", &InvalidParamsError{"schema plan pull", "missing required flag --url"}
}
return stringVal(c.runCommand(ctx, args))
}
// SchemaPlanLint runs the `schema plan lint` command.
func (c *Client) SchemaPlanLint(ctx context.Context, params *SchemaPlanLintParams) (*SchemaPlan, error) {
args := []string{"schema", "plan", "lint", "--format", "{{ json . }}"}
// Global flags
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
// Hidden flags
if params.Context != nil {
buf, err := json.Marshal(params.Context)
if err != nil {
return nil, err
}
args = append(args, "--context", string(buf))
}
// Flags of the 'schema plan lint' sub-commands
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if len(params.Schema) > 0 {
args = append(args, "--schema", listString(params.Schema))
}
if len(params.Exclude) > 0 {
args = append(args, "--exclude", listString(params.Exclude))
}
if len(params.Include) > 0 {
args = append(args, "--include", listString(params.Include))
}
if len(params.From) > 0 {
args = append(args, "--from", listString(params.From))
}
if len(params.To) > 0 {
args = append(args, "--to", listString(params.To))
}
if params.File != "" {
args = append(args, "--file", params.File)
} else {
return nil, &InvalidParamsError{"schema plan lint", "missing required flag --file"}
}
if params.Repo != "" {
args = append(args, "--repo", params.Repo)
}
args = append(args, "--auto-approve")
// NOTE: This command only support one result.
return firstResult(jsonDecode[SchemaPlan](c.runCommand(ctx, args)))
}
// SchemaPlanValidate runs the `schema plan validate` command.
func (c *Client) SchemaPlanValidate(ctx context.Context, params *SchemaPlanValidateParams) error {
args := []string{"schema", "plan", "validate"}
// Global flags
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
// Hidden flags
if params.Context != nil {
buf, err := json.Marshal(params.Context)
if err != nil {
return err
}
args = append(args, "--context", string(buf))
}
// Flags of the 'schema plan validate' sub-commands
if params.DevURL != "" {
args = append(args, "--dev-url", params.DevURL)
}
if len(params.Schema) > 0 {
args = append(args, "--schema", listString(params.Schema))
}
if len(params.Exclude) > 0 {
args = append(args, "--exclude", listString(params.Exclude))
}
if len(params.Include) > 0 {
args = append(args, "--include", listString(params.Include))
}
if len(params.From) > 0 {
args = append(args, "--from", listString(params.From))
}
if len(params.To) > 0 {
args = append(args, "--to", listString(params.To))
}
if params.File != "" {
args = append(args, "--file", params.File)
} else {
return &InvalidParamsError{"schema plan validate", "missing required flag --file"}
}
if params.Name != "" {
args = append(args, "--name", params.Name)
}
if params.Repo != "" {
args = append(args, "--repo", params.Repo)
}
args = append(args, "--auto-approve")
_, err := stringVal(c.runCommand(ctx, args))
return err
}
// SchemaPlanApprove runs the `schema plan approve` command.
func (c *Client) SchemaPlanApprove(ctx context.Context, params *SchemaPlanApproveParams) (*SchemaPlanApprove, error) {
args := []string{"schema", "plan", "approve", "--format", "{{ json . }}"}
// Global flags
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
// Flags of the 'schema plan approve' sub-commands
if params.URL != "" {
args = append(args, "--url", params.URL)
} else {
return nil, &InvalidParamsError{"schema plan approve", "missing required flag --url"}
}
// NOTE: This command only support one result.
return firstResult(jsonDecode[SchemaPlanApprove](c.runCommand(ctx, args)))
}
// SchemaClean runs the `schema clean` command.
func (c *Client) SchemaClean(ctx context.Context, params *SchemaCleanParams) (*SchemaClean, error) {
args := []string{"schema", "clean", "--format", "{{ json . }}"}
// Global flags
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
// Flags of the 'schema clean' sub-commands
if params.URL != "" {
args = append(args, "--url", params.URL)
}
switch {
case params.DryRun:
args = append(args, "--dry-run")
case params.AutoApprove:
args = append(args, "--auto-approve")
}
return firstResult(jsonDecode[SchemaClean](c.runCommand(ctx, args)))
}
// SchemaLint runs the 'schema lint' command.
func (c *Client) SchemaLint(ctx context.Context, params *SchemaLintParams) (*SchemaLintReport, error) {
args, err := params.AsArgs()
if err != nil {
return nil, err
}
return firstResult(jsonDecode[SchemaLintReport](c.runCommand(ctx, args)))
}
// SchemaStatsInspect runs the 'schema stats inspect' command.
func (c *Client) SchemaStatsInspect(ctx context.Context, params *SchemaStatsInspectParams) (string, error) {
args := []string{"schema", "stats", "inspect", "--format", "{{ json .Realm }}"}
if params.Env != "" {
args = append(args, "--env", params.Env)
}
if params.ConfigURL != "" {
args = append(args, "--config", params.ConfigURL)
}
if params.URL != "" {
args = append(args, "--url", params.URL)
}
if len(params.Schema) > 0 {
args = append(args, "--schema", listString(params.Schema))
}
if len(params.Exclude) > 0 {
args = append(args, "--exclude", listString(params.Exclude))
}
if len(params.Include) > 0 {
args = append(args, "--include", listString(params.Include))
}
if params.Vars != nil {
args = append(args, params.Vars.AsArgs()...)
}
return stringVal(c.runCommand(ctx, args))
}
// AsArgs returns the parameters as arguments.
func (p *SchemaLintParams) AsArgs() ([]string, error) {
args := []string{"schema", "lint", "--format", "{{ json . }}"}
if p.Env != "" {
args = append(args, "--env", p.Env)
}
if p.ConfigURL != "" {
args = append(args, "--config", p.ConfigURL)
}
if p.DevURL != "" {
args = append(args, "--dev-url", p.DevURL)
}
args = append(args, repeatFlag("--url", p.URL)...)
if len(p.Schema) > 0 {
args = append(args, "--schema", listString(p.Schema))
}
if p.Vars != nil {
args = append(args, p.Vars.AsArgs()...)
}
return args, nil
}
// InvalidParamsError is an error type for invalid parameters.
type InvalidParamsError struct {
cmd string
msg string
}
// Error returns the error message.
func (e *InvalidParamsError) Error() string {
return fmt.Sprintf("atlasexec: command %q has invalid parameters: %v", e.cmd, e.msg)
}
func newSchemaApplyError(r []*SchemaApply, stderr string) error {
return &SchemaApplyError{Result: r, Stderr: stderr}
}
// Error implements the error interface.
func (e *SchemaApplyError) Error() string {
var errs []string
for _, r := range e.Result {
if r.Error != "" {
errs = append(errs, r.Error)
}
}
if e.Stderr != "" {
errs = append(errs, e.Stderr)
}
return strings.Join(errs, "\n")
}
================================================
FILE: atlasexec/atlas_schema_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec_test
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"ariga.io/atlas/atlasexec"
"github.com/stretchr/testify/require"
)
func TestSchema_Test(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
for _, tt := range []struct {
name string
params *atlasexec.SchemaTestParams
args string
stdout string
}{
{
name: "no params",
params: &atlasexec.SchemaTestParams{},
args: "schema test",
stdout: "test result",
},
{
name: "with env",
params: &atlasexec.SchemaTestParams{
Env: "test",
},
args: "schema test --env test",
stdout: "test result",
},
{
name: "with config",
params: &atlasexec.SchemaTestParams{
ConfigURL: "file://config.hcl",
},
args: "schema test --config file://config.hcl",
stdout: "test result",
},
{
name: "with dev-url",
params: &atlasexec.SchemaTestParams{
DevURL: "sqlite://file?_fk=1&cache=shared&mode=memory",
},
args: "schema test --dev-url sqlite://file?_fk=1&cache=shared&mode=memory",
stdout: "test result",
},
{
name: "with run",
params: &atlasexec.SchemaTestParams{
Run: "example",
},
args: "schema test --run example",
stdout: "test result",
},
{
name: "with run and paths",
params: &atlasexec.SchemaTestParams{
Run: "example",
Paths: []string{"./foo", "./bar"},
},
args: "schema test --run example ./foo ./bar",
stdout: "test result",
},
} {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", tt.stdout)
result, err := c.SchemaTest(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, tt.stdout, result)
})
}
}
func TestSchema_Inspect(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
for _, tt := range []struct {
name string
params *atlasexec.SchemaInspectParams
args string
stdout string
}{
{
name: "no params",
params: &atlasexec.SchemaInspectParams{},
args: "schema inspect",
stdout: `schema "public" {}`,
},
{
name: "with env",
params: &atlasexec.SchemaInspectParams{
Env: "test",
},
args: "schema inspect --env test",
stdout: `schema "public" {}`,
},
{
name: "with config",
params: &atlasexec.SchemaInspectParams{
ConfigURL: "file://config.hcl",
Env: "test",
},
args: "schema inspect --env test --config file://config.hcl",
stdout: `schema "public" {}`,
},
} {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", tt.stdout)
result, err := c.SchemaInspect(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, tt.stdout, result)
})
}
}
func TestAtlasSchema_Apply(t *testing.T) {
ce, err := atlasexec.NewWorkingDir()
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, ce.Close())
})
f, err := os.CreateTemp("", "sqlite-test")
require.NoError(t, err)
defer os.Remove(f.Name())
u := fmt.Sprintf("sqlite://%s?_fk=1", f.Name())
c, err := atlasexec.NewClient(ce.Path(), "atlas")
require.NoError(t, err)
s1 := `
-- create table "users
CREATE TABLE users(
id int NOT NULL,
name varchar(100) NULL,
PRIMARY KEY(id)
);`
path, err := ce.WriteFile("schema.sql", []byte(s1))
to := fmt.Sprintf("file://%s", path)
require.NoError(t, err)
_, err = c.SchemaApply(context.Background(), &atlasexec.SchemaApplyParams{
URL: u,
To: to,
DevURL: "sqlite://file?_fk=1&cache=shared&mode=memory",
AutoApprove: true,
})
require.NoError(t, err)
_, err = ce.WriteFile("schema.sql", []byte(s1+`
-- create table "blog_posts"
CREATE TABLE blog_posts(
id int NOT NULL,
title varchar(100) NULL,
body text NULL,
author_id int NULL,
PRIMARY KEY(id),
CONSTRAINT author_fk FOREIGN KEY(author_id) REFERENCES users(id)
);`))
require.NoError(t, err)
_, err = c.SchemaApply(context.Background(), &atlasexec.SchemaApplyParams{
URL: u,
To: to,
DevURL: "sqlite://file?_fk=1&cache=shared&mode=memory",
AutoApprove: true,
})
require.NoError(t, err)
s, err := c.SchemaInspect(context.Background(), &atlasexec.SchemaInspectParams{
URL: u,
})
require.NoError(t, err)
require.Equal(t, `table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
column "name" {
null = true
type = varchar
}
primary_key {
columns = [column.id]
}
}
table "blog_posts" {
schema = schema.main
column "id" {
null = false
type = int
}
column "title" {
null = true
type = varchar
}
column "body" {
null = true
type = text
}
column "author_id" {
null = true
type = int
}
primary_key {
columns = [column.id]
}
foreign_key "author_fk" {
columns = [column.author_id]
ref_columns = [table.users.column.id]
on_update = NO_ACTION
on_delete = NO_ACTION
}
}
schema "main" {
}
`, s)
}
func TestSchema_Plan(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
testCases := []struct {
name string
params *atlasexec.SchemaPlanParams
args string
}{
{
name: "no params",
params: &atlasexec.SchemaPlanParams{},
args: "schema plan --format {{ json . }} --auto-approve",
},
{
name: "with env",
params: &atlasexec.SchemaPlanParams{
Env: "test",
},
args: "schema plan --format {{ json . }} --env test --auto-approve",
},
{
name: "with from to",
params: &atlasexec.SchemaPlanParams{
From: []string{"1", "2"},
To: []string{"2", "3"},
},
args: `schema plan --format {{ json . }} --from 1,2 --to 2,3 --auto-approve`,
},
{
name: "with from to and schema",
params: &atlasexec.SchemaPlanParams{
From: []string{"1", "2"},
To: []string{"2", "3"},
Schema: []string{"public", "bupisu"},
},
args: `schema plan --format {{ json . }} --schema public,bupisu --from 1,2 --to 2,3 --auto-approve`,
},
{
name: "with from to and directives",
params: &atlasexec.SchemaPlanParams{
From: []string{"1", "2"},
To: []string{"2", "3"},
Directives: []string{"atlas:nolint", "atlas:txmode none"},
},
args: `schema plan --format {{ json . }} --from 1,2 --to 2,3 --auto-approve --directive "atlas:nolint" --directive "atlas:txmode none"`,
},
{
name: "with config",
params: &atlasexec.SchemaPlanParams{
ConfigURL: "file://config.hcl",
},
args: "schema plan --format {{ json . }} --config file://config.hcl --auto-approve",
},
{
name: "with dev-url",
params: &atlasexec.SchemaPlanParams{
DevURL: "sqlite://file?_fk=1&cache=shared&mode=memory",
},
args: "schema plan --format {{ json . }} --dev-url sqlite://file?_fk=1&cache=shared&mode=memory --auto-approve",
},
{
name: "with name",
params: &atlasexec.SchemaPlanParams{
Name: "example",
},
args: "schema plan --format {{ json . }} --name example --auto-approve",
},
{
name: "with dry-run",
params: &atlasexec.SchemaPlanParams{
DryRun: true,
},
args: "schema plan --format {{ json . }} --dry-run",
},
{
name: "with save",
params: &atlasexec.SchemaPlanParams{
Save: true,
},
args: "schema plan --format {{ json . }} --save --auto-approve",
},
{
name: "with push",
params: &atlasexec.SchemaPlanParams{
Repo: "testing-repo",
Push: true,
},
args: "schema plan --format {{ json . }} --repo testing-repo --push --auto-approve",
},
{
name: "with include",
params: &atlasexec.SchemaPlanParams{
Include: []string{"public", "bupisu"},
},
args: "schema plan --format {{ json . }} --include public,bupisu --auto-approve",
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", `{"Repo":"foo"}`)
result, err := c.SchemaPlan(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, "foo", result.Repo)
})
}
}
func TestSchema_PlanPush(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
testCases := []struct {
name string
params *atlasexec.SchemaPlanPushParams
args string
}{
{
name: "with auto-approve",
params: &atlasexec.SchemaPlanPushParams{
Repo: "testing-repo",
File: "file://plan.hcl",
},
args: "schema plan push --format {{ json . }} --file file://plan.hcl --repo testing-repo --auto-approve",
},
{
name: "with auto-approve and schema",
params: &atlasexec.SchemaPlanPushParams{
Repo: "testing-repo",
File: "file://plan.hcl",
Schema: []string{"public", "bupisu"},
},
args: "schema plan push --format {{ json . }} --schema public,bupisu --file file://plan.hcl --repo testing-repo --auto-approve",
},
{
name: "with pending status",
params: &atlasexec.SchemaPlanPushParams{
Pending: true,
File: "file://plan.hcl",
},
args: "schema plan push --format {{ json . }} --file file://plan.hcl --pending",
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", `{"Repo":"foo"}`)
result, err := c.SchemaPlanPush(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, `{"Repo":"foo"}`, result)
})
}
}
func TestSchema_PlanLint(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
testCases := []struct {
name string
params *atlasexec.SchemaPlanLintParams
args string
}{
{
name: "with repo",
params: &atlasexec.SchemaPlanLintParams{
Repo: "testing-repo",
File: "file://plan.hcl",
},
args: "schema plan lint --format {{ json . }} --file file://plan.hcl --repo testing-repo --auto-approve",
},
{
name: "with file only",
params: &atlasexec.SchemaPlanLintParams{
File: "file://plan.hcl",
},
args: "schema plan lint --format {{ json . }} --file file://plan.hcl --auto-approve",
},
{
name: "with file and schema",
params: &atlasexec.SchemaPlanLintParams{
File: "file://plan.hcl",
Schema: []string{"public", "bupisu"},
},
args: "schema plan lint --format {{ json . }} --schema public,bupisu --file file://plan.hcl --auto-approve",
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", `{"Repo":"foo"}`)
result, err := c.SchemaPlanLint(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, "foo", result.Repo)
})
}
}
func TestSchema_PlanValidate(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
testCases := []struct {
name string
params *atlasexec.SchemaPlanValidateParams
args string
}{
{
name: "with repo",
params: &atlasexec.SchemaPlanValidateParams{
Repo: "testing-repo",
File: "file://plan.hcl",
},
args: "schema plan validate --file file://plan.hcl --repo testing-repo --auto-approve",
},
{
name: "with file only",
params: &atlasexec.SchemaPlanValidateParams{
File: "file://plan.hcl",
},
args: "schema plan validate --file file://plan.hcl --auto-approve",
},
{
name: "with file and schema",
params: &atlasexec.SchemaPlanValidateParams{
File: "file://plan.hcl",
Schema: []string{"public", "bupisu"},
},
args: "schema plan validate --schema public,bupisu --file file://plan.hcl --auto-approve",
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", `{"Repo":"foo"}`)
err := c.SchemaPlanValidate(context.Background(), tt.params)
require.NoError(t, err)
})
}
}
func TestSchema_PlanApprove(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
testCases := []struct {
name string
params *atlasexec.SchemaPlanApproveParams
args string
}{
{
name: "with url",
params: &atlasexec.SchemaPlanApproveParams{
URL: "atlas://app1/plans/foo-plan",
},
args: "schema plan approve --format {{ json . }} --url atlas://app1/plans/foo-plan",
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", `{"URL":"atlas://app1/plans/foo-plan", "Link":"some-link", "Status":"APPROVED"}`)
result, err := c.SchemaPlanApprove(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, "atlas://app1/plans/foo-plan", result.URL)
})
}
}
func TestSchema_PlanPull(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
testCases := []struct {
name string
params *atlasexec.SchemaPlanPullParams
args string
}{
{
name: "with url",
params: &atlasexec.SchemaPlanPullParams{
URL: "atlas://app1/plans/foo-plan",
},
args: "schema plan pull --url atlas://app1/plans/foo-plan",
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", "excited-plan")
result, err := c.SchemaPlanPull(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, "excited-plan", result)
})
}
}
func TestSchema_PlanList(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
testCases := []struct {
name string
params *atlasexec.SchemaPlanListParams
args string
}{
{
name: "no params",
params: &atlasexec.SchemaPlanListParams{},
args: "schema plan list --format {{ json . }} --auto-approve",
},
{
name: "with repo",
params: &atlasexec.SchemaPlanListParams{
Repo: "atlas://testing-repo",
From: []string{"env://url"},
},
args: "schema plan list --format {{ json . }} --from env://url --repo atlas://testing-repo --auto-approve",
},
{
name: "with repo and schema",
params: &atlasexec.SchemaPlanListParams{
Repo: "atlas://testing-repo",
From: []string{"env://url"},
Schema: []string{"public", "bupisu"},
},
args: "schema plan list --format {{ json . }} --schema public,bupisu --from env://url --repo atlas://testing-repo --auto-approve",
},
{
name: "with repo and pending",
params: &atlasexec.SchemaPlanListParams{
Repo: "atlas://testing-repo",
Pending: true,
},
args: "schema plan list --format {{ json . }} --repo atlas://testing-repo --pending --auto-approve",
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", `[{"Name":"pr-2-ufnTS7Nr"}]`)
result, err := c.SchemaPlanList(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, "pr-2-ufnTS7Nr", result[0].Name)
})
}
}
func TestSchema_Push(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
testCases := []struct {
name string
params *atlasexec.SchemaPushParams
args string
}{
{
name: "no params",
params: &atlasexec.SchemaPushParams{},
args: "schema push --format {{ json . }}",
},
{
name: "push with 1 URL",
params: &atlasexec.SchemaPushParams{
URL: []string{"file://foo.hcl"},
},
args: "schema push --format {{ json . }} --url file://foo.hcl",
},
{
name: "push with 2 URLs",
params: &atlasexec.SchemaPushParams{
URL: []string{"file://foo.hcl", "file://bupisu.hcl"},
},
args: "schema push --format {{ json . }} --url file://foo.hcl --url file://bupisu.hcl",
},
{
name: "with repo",
params: &atlasexec.SchemaPushParams{
Name: "atlas-action",
},
args: "schema push --format {{ json . }} atlas-action",
},
{
name: "with repo and schemas",
params: &atlasexec.SchemaPushParams{
Name: "atlas-action",
Schema: []string{"public", "bupisu"},
},
args: "schema push --format {{ json . }} --schema public,bupisu atlas-action",
},
{
name: "with repo and tag",
params: &atlasexec.SchemaPushParams{
Name: "atlas-action",
Tag: "v1.0.0",
},
args: "schema push --format {{ json . }} --tag v1.0.0 atlas-action",
},
{
name: "with repo and tag and description",
params: &atlasexec.SchemaPushParams{
Name: "atlas-action",
Tag: "v1.0.0",
Description: "release-v1",
},
args: "schema push --format {{ json . }} --tag v1.0.0 --desc release-v1 atlas-action",
},
{
name: "with repo and tag, version and description",
params: &atlasexec.SchemaPushParams{
Name: "atlas-action",
Tag: "v1.0.0",
Version: "20240829100417",
Description: "release-v1",
},
args: "schema push --format {{ json . }} --tag v1.0.0 --version 20240829100417 --desc release-v1 atlas-action",
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", `{"Link":"https://gh.atlasgo.cloud/schemas/141733920810","Slug":"awesome-app","URL":"atlas://awesome-app?tag=latest"}`)
result, err := c.SchemaPush(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, "https://gh.atlasgo.cloud/schemas/141733920810", result.Link)
require.Equal(t, "atlas://awesome-app?tag=latest", result.URL)
require.Equal(t, "awesome-app", result.Slug)
})
}
}
func TestSchema_Apply(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
testCases := []struct {
name string
params *atlasexec.SchemaApplyParams
args string
}{
{
name: "no params",
params: &atlasexec.SchemaApplyParams{},
args: "schema apply --format {{ json . }}",
},
{
name: "with plan",
params: &atlasexec.SchemaApplyParams{
PlanURL: "atlas://app1/plans/foo-plan",
},
args: "schema apply --format {{ json . }} --plan atlas://app1/plans/foo-plan",
},
{
name: "with auto-approve",
params: &atlasexec.SchemaApplyParams{
AutoApprove: true,
},
args: "schema apply --format {{ json . }} --auto-approve",
},
{
name: "with lock name",
params: &atlasexec.SchemaApplyParams{
LockName: "custom_schema_lock",
},
args: "schema apply --format {{ json . }} --lock-name custom_schema_lock",
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", `{"Driver":"sqlite"}`)
result, err := c.SchemaApply(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, "sqlite", result.Driver)
})
}
}
func TestSchema_Clean(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
testCases := []struct {
name string
params *atlasexec.SchemaCleanParams
args string
}{
{
name: "with env and dry-run",
params: &atlasexec.SchemaCleanParams{
Env: "test",
URL: "sqlite://app1.db",
DryRun: true,
},
args: "schema clean --format {{ json . }} --env test --url sqlite://app1.db --dry-run",
},
{
name: "with auto-approve",
params: &atlasexec.SchemaCleanParams{
URL: "sqlite://app1.db",
AutoApprove: true,
},
args: "schema clean --format {{ json . }} --url sqlite://app1.db --auto-approve",
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", "{\"Start\":\"2024-09-20T14:51:40.439499+07:00\",\"End\":\"2024-09-20T14:51:40.439533+07:00\",\"Applied\":{\"Name\":\"20240920075140.sql\",\"Version\":\"20240920075140\",\"Start\":\"2024-09-20T14:51:40.43952+07:00\",\"End\":\"2024-09-20T14:51:40.439533+07:00\",\"Applied\":[\"PRAGMA foreign_keys = off;\",\"DROP TABLE `t1`;\", \"PRAGMA foreign_keys = on;\"]}}")
result, err := c.SchemaClean(context.Background(), tt.params)
require.NoError(t, err)
require.Equal(t, "20240920075140.sql", result.Applied.Name)
})
}
}
func TestSchema_ApplyEnvs(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
require.NoError(t, c.SetEnv(map[string]string{
"TEST_ARGS": "schema apply --format {{ json . }} --env test",
"TEST_STDOUT": `{"Driver":"sqlite","URL":{"Scheme":"sqlite","Host":"local-su.db"}}
{"Driver":"sqlite","URL":{"Scheme":"sqlite","Host":"local-pi.db"}}
{"Driver":"sqlite","URL":{"Scheme":"sqlite","Host":"local-bu.db"}}`,
"TEST_STDERR": `Abort: The plan "From" hash does not match the current state hash (passed with --from):
[31m- iHZMQ1EoarAXt/KU0KQbBljbbGs8gVqX2ZBXefePSGE=[0m[90m (plan value)[0m
[32m+ Cp8xCVYilZuwULkggsfJLqIQHaxYcg/IpU+kgjVUBA4=[0m[90m (current hash)[0m
`,
}))
result, err := c.SchemaApply(context.Background(), &atlasexec.SchemaApplyParams{
Env: "test",
})
require.ErrorContains(t, err, `The plan "From" hash does not match the current state hash`)
require.Nil(t, result)
err2, ok := err.(*atlasexec.SchemaApplyError)
require.True(t, ok, "should be a SchemaApplyError, got %T", err)
require.Contains(t, err2.Stderr, `Abort: The plan "From" hash does not match the current state hash (passed with --from)`)
require.Len(t, err2.Result, 3, "should returns succeed results")
require.Equal(t, "sqlite://local-su.db", err2.Result[0].URL.String())
require.Equal(t, "sqlite://local-pi.db", err2.Result[1].URL.String())
require.Equal(t, "sqlite://local-bu.db", err2.Result[2].URL.String())
}
func TestSchemaApplyError_Error(t *testing.T) {
t.Run("single result error only", func(t *testing.T) {
e := &atlasexec.SchemaApplyError{
Result: []*atlasexec.SchemaApply{
{Error: "schema apply failed"},
},
}
require.Equal(t, "schema apply failed", e.Error())
})
t.Run("stderr only", func(t *testing.T) {
e := &atlasexec.SchemaApplyError{
Stderr: "Error: unable to acquire lock",
}
require.Equal(t, "Error: unable to acquire lock", e.Error())
})
t.Run("single result error and stderr", func(t *testing.T) {
e := &atlasexec.SchemaApplyError{
Result: []*atlasexec.SchemaApply{
{Error: "schema apply failed"},
},
Stderr: "Error: unable to acquire lock",
}
require.Equal(t, "schema apply failed\nError: unable to acquire lock", e.Error())
})
t.Run("multiple result errors and stderr", func(t *testing.T) {
e := &atlasexec.SchemaApplyError{
Result: []*atlasexec.SchemaApply{
{Error: "error on target 1"},
{Error: "error on target 2"},
},
Stderr: "Error: unable to acquire lock",
}
require.Equal(t, "error on target 1\nerror on target 2\nError: unable to acquire lock", e.Error())
})
t.Run("multiple results with some having no error", func(t *testing.T) {
e := &atlasexec.SchemaApplyError{
Result: []*atlasexec.SchemaApply{
{Error: ""},
{Error: "error on target 2"},
{Error: ""},
},
Stderr: "Error: unable to acquire lock",
}
require.Equal(t, "error on target 2\nError: unable to acquire lock", e.Error())
})
t.Run("no errors at all", func(t *testing.T) {
e := &atlasexec.SchemaApplyError{
Result: []*atlasexec.SchemaApply{
{Error: ""},
},
}
require.Equal(t, "", e.Error())
})
t.Run("nil result with stderr", func(t *testing.T) {
e := &atlasexec.SchemaApplyError{
Stderr: "Error: connection refused",
}
require.Equal(t, "Error: connection refused", e.Error())
})
}
func TestAtlasSchema_Lint(t *testing.T) {
t.Run("with broken config", func(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
_, err = c.SchemaLint(context.Background(), &atlasexec.SchemaLintParams{
ConfigURL: "file://config-broken.hcl",
})
require.ErrorContains(t, err, `file "config-broken.hcl" was not found`)
})
t.Run("with missing dev-url", func(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
_, err = c.SchemaLint(context.Background(), &atlasexec.SchemaLintParams{
URL: []string{"file://testdata/schema.hcl"},
})
require.ErrorContains(t, err, `required flag(s) "dev-url" not set`)
})
var (
atlashcl = filepath.Join(t.TempDir(), "atlas.hcl")
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintln(w, `{"data": {"me":{ "name": "p", "org": "life"}}}`)
}))
)
t.Cleanup(srv.Close)
require.NoError(t, os.WriteFile(atlashcl, []byte(fmt.Sprintf(`
atlas {
cloud {
token = "aci_token"
url = %q
org = "life"
}
}
lint {
naming {
table {
match = "^[a-z_]+$"
}
}
}`, srv.URL)), 0600))
t.Run("with non-existent schema file", func(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
_, err = c.SchemaLint(context.Background(), &atlasexec.SchemaLintParams{
ConfigURL: "file://" + atlashcl,
DevURL: "sqlite://file?mode=memory",
URL: []string{"file://testdata/doesnotexist.hcl"},
})
require.ErrorContains(t, err, "Error: stat testdata/doesnotexist.hcl: no such file or directory")
})
t.Run("with schema containing problems", func(t *testing.T) {
c, err := atlasexec.NewClient(".", "atlas")
require.NoError(t, err)
report, err := c.SchemaLint(context.Background(), &atlasexec.SchemaLintParams{
ConfigURL: "file://" + atlashcl,
DevURL: "sqlite://file?mode=memory",
URL: []string{sqlitedb(t, "create table T1(id int);")},
})
require.NoError(t, err)
require.NotNil(t, report)
require.NotEmpty(t, report.Steps)
require.Len(t, report.Steps, 1)
require.Len(t, report.Steps[0].Diagnostics, 1)
require.Equal(t, "Table \"main.T1\" violates the naming policy", report.Steps[0].Diagnostics[0].Text)
require.Equal(t, "NM102", report.Steps[0].Diagnostics[0].Code)
})
}
func TestSchema_Lint(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
testCases := []struct {
name string
params *atlasexec.SchemaLintParams
args string
}{
{
name: "with dev-url and url",
params: &atlasexec.SchemaLintParams{
URL: []string{"file://testdata/schema.hcl"},
DevURL: "sqlite://file?mode=memory",
},
args: "schema lint --format {{ json . }} --dev-url sqlite://file?mode=memory --url file://testdata/schema.hcl",
},
{
name: "with dev-url and url and schema",
params: &atlasexec.SchemaLintParams{
URL: []string{"file://testdata/schema.hcl"},
DevURL: "sqlite://file?mode=memory",
Schema: []string{"main", "bupisu"},
},
args: "schema lint --format {{ json . }} --dev-url sqlite://file?mode=memory --url file://testdata/schema.hcl --schema main,bupisu",
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_ARGS", tt.args)
t.Setenv("TEST_STDOUT", `{"Steps":[{"Diagnostics":[{"Text":"Table \"main.T1\" violates the naming policy","Code":"NM102"}]}]}`)
result, err := c.SchemaLint(context.Background(), tt.params)
require.NoError(t, err)
require.NotNil(t, result)
require.NotEmpty(t, result.Steps)
require.Len(t, result.Steps, 1)
require.Len(t, result.Steps[0].Diagnostics, 1)
require.Equal(t, "Table \"main.T1\" violates the naming policy", result.Steps[0].Diagnostics[0].Text)
})
}
}
================================================
FILE: atlasexec/atlas_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec_test
import (
"context"
"database/sql"
"fmt"
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
"testing"
"ariga.io/atlas/atlasexec"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
)
func TestError(t *testing.T) {
err := atlasexec.Error{}
require.NotPanics(t, func() {
err.ExitCode()
})
}
func TestNewClient(t *testing.T) {
execPath, err := exec.LookPath("atlas")
require.NoError(t, err)
// Test that we can create a client with a custom exec path.
_, err = atlasexec.NewClient(t.TempDir(), execPath)
require.NoError(t, err)
// Atlas-CLI is installed in the PATH.
_, err = atlasexec.NewClient(t.TempDir(), "atlas")
require.NoError(t, err)
// Atlas-CLI is not found for the given exec path.
_, err = atlasexec.NewClient(t.TempDir(), "/foo/atlas")
require.ErrorContains(t, err, `no such file or directory`)
}
func TestVersion(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
for _, tt := range []struct {
env string
expect *atlasexec.Version
}{
{
env: "v1.2.3",
expect: &atlasexec.Version{Version: "1.2.3"},
},
{
env: "v0.14.1-abcdef-canary",
expect: &atlasexec.Version{
Version: "0.14.1",
SHA: "abcdef",
Canary: true,
},
},
{
env: "v11.22.33-sha",
expect: &atlasexec.Version{
Version: "11.22.33",
SHA: "sha",
},
},
} {
t.Run(tt.env, func(t *testing.T) {
t.Setenv("TEST_ARGS", "version")
t.Setenv("TEST_STDOUT", fmt.Sprintf("atlas version %s", tt.env))
v, err := c.Version(context.Background())
require.NoError(t, err)
require.Equal(t, tt.expect, v)
if tt.env != "" {
require.Equal(t, "atlas version "+tt.env, v.String())
}
})
}
}
func TestLogin(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
// Empty token returns error without invoking the binary.
err = c.Login(context.Background(), &atlasexec.LoginParams{Token: ""})
require.Error(t, err)
require.Contains(t, err.Error(), "token cannot be empty")
// Login with token only: must pass "login --token ".
t.Run("token_only", func(t *testing.T) {
t.Setenv("TEST_ARGS", "login --token my-token")
t.Setenv("TEST_STDOUT", "ok")
t.Setenv("TEST_STDERR", "")
err := c.Login(context.Background(), &atlasexec.LoginParams{Token: "my-token"})
require.NoError(t, err)
})
// Login with token and GrantOnly: must pass "login --token --grant-only".
t.Run("grant_only", func(t *testing.T) {
t.Setenv("TEST_ARGS", "login --token my-token --grant-only")
t.Setenv("TEST_STDOUT", "ok")
t.Setenv("TEST_STDERR", "")
err := c.Login(context.Background(), &atlasexec.LoginParams{Token: "my-token", GrantOnly: true})
require.NoError(t, err)
})
}
func TestWhoAmI(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
t.Setenv("TEST_ARGS", "whoami --format {{ json . }}")
// Test success.
t.Setenv("TEST_STDOUT", `{"Org":"boring"}`)
v, err := c.WhoAmI(context.Background(), &atlasexec.WhoAmIParams{})
require.NoError(t, err)
require.NotNil(t, v)
require.Equal(t, "boring", v.Org)
// Test error.
t.Setenv("TEST_STDOUT", "")
t.Setenv("TEST_STDERR", `Error: command requires 'atlas login'`)
_, err = c.WhoAmI(context.Background(), &atlasexec.WhoAmIParams{})
require.EqualError(t, err, "command requires 'atlas login'")
require.ErrorIs(t, err, atlasexec.ErrRequireLogin)
// Test config url
t.Setenv("TEST_ARGS", "whoami --format {{ json . }} --config file://config.hcl --env local --var foo=bar")
t.Setenv("TEST_STDOUT", `{"Org":"boring"}`)
t.Setenv("TEST_STDERR", "")
v, err = c.WhoAmI(context.Background(), &atlasexec.WhoAmIParams{
ConfigURL: "file://config.hcl",
Env: "local",
Vars: atlasexec.Vars{"foo": "bar"},
})
require.NoError(t, err)
require.NotNil(t, v)
require.Equal(t, "boring", v.Org)
}
func TestVars2(t *testing.T) {
var vars = atlasexec.Vars2{
"key1": "value1",
"key2": "value2",
"key3": []string{"value3", "value4"},
"key4": 100,
"key5": []int{1, 2, 3},
"key6": []stringer{{}, {}},
}
require.Equal(t, []string{
"--var", "key1=value1",
"--var", "key2=value2",
"--var", "key3=value3",
"--var", "key3=value4",
"--var", "key4=100",
"--var", "key5=1",
"--var", "key5=2",
"--var", "key5=3",
"--var", "key6=foo",
"--var", "key6=foo",
}, vars.AsArgs())
}
func generateHCL(t *testing.T, token string, srv *httptest.Server) string {
st := fmt.Sprintf(
`atlas {
cloud {
token = %q
url = %q
}
}
env "test" {}
`, token, srv.URL)
atlasConfigURL, clean, err := atlasexec.TempFile(st, "hcl")
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, clean())
})
return atlasConfigURL
}
func sqlitedb(t *testing.T, seed string) string {
td := t.TempDir()
dsn := fmt.Sprintf("file:%s?cache=shared&_fk=1", filepath.Join(td, "file.db"))
db, err := sql.Open("sqlite3", dsn)
require.NoError(t, err)
if seed != "" {
_, err = db.ExecContext(context.Background(), seed)
require.NoError(t, err)
}
return fmt.Sprintf("sqlite://%s", dsn)
}
type stringer struct{}
func (s stringer) String() string {
return "foo"
}
================================================
FILE: atlasexec/copilot.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec
import (
"context"
"encoding/json"
"strings"
)
// CopilotTypeMessage, CopilotTypeToolCall, and CopilotTypeToolOutput are the
// types of messages that can be emitted by the Copilot execution.
const (
CopilotTypeMessage = "message"
CopilotTypeToolCall = "tool_call"
CopilotTypeToolOutput = "tool_output"
)
type (
// CopilotParams are the parameters for the Copilot execution.
CopilotParams struct {
Prompt, Session string
// FSWrite and FSDelete glob patterns to specify file permissions.
FSWrite, FSDelete string
}
// Copilot is the result of a Copilot execution.
Copilot []*CopilotMessage
// CopilotMessage is the JSON message emitted by the Copilot OneShot execution.
CopilotMessage struct {
// Session ID for the Copilot session.
SessionID string `json:"sessionID,omitempty"`
// Type of the message. Can be "message", "tool_call", or "tool_output".
Type string `json:"type"`
// Content, ToolCall and ToolOutput are mutually exclusive.
Content string `json:"content,omitempty"`
ToolCall *ToolCallMessage `json:"toolCall,omitempty"`
ToolOutput *ToolOutputMessage `json:"toolOutput,omitempty"`
}
// ToolCallMessage is the input to a tool call.
ToolCallMessage struct {
CallID string `json:"callID"`
Function string `json:"function"`
Arguments string `json:"arguments"`
}
// ToolOutputMessage is the output of a tool call.
ToolOutputMessage struct {
CallID string `json:"callID"`
Content string `json:"content"`
}
)
// Copilot executes a one-shot Copilot session with the provided options.
func (c *Client) Copilot(ctx context.Context, params *CopilotParams) (Copilot, error) {
args := []string{"copilot", "-q", params.Prompt}
if params.Session != "" {
args = append(args, "-r", params.Session)
}
if params.FSWrite != "" {
args = append(args, "-p", "fs.write="+params.FSWrite)
}
if params.FSDelete != "" {
args = append(args, "-p", "fs.delete="+params.FSDelete)
}
return jsonDecode[CopilotMessage](c.runCommand(ctx, args))
}
type copilotStream struct {
s Stream[string]
cur *CopilotMessage
err error
}
// Next advances the stream to the next CopilotMessage.
func (s *copilotStream) Next() bool {
s.cur = nil
s.err = nil
return s.s.Next()
}
// Current returns the current CopilotMessage from the stream.
func (s *copilotStream) Current() (*CopilotMessage, error) {
if s.err != nil {
return nil, s.err
}
if s.cur == nil {
cur, err := s.s.Current()
if err != nil {
s.err = err
return nil, err
}
var m CopilotMessage
if s.err = json.Unmarshal([]byte(cur), &m); s.err != nil {
return nil, s.err
}
s.cur = &m
}
return s.cur, nil
}
// Err returns the error encountered during the stream processing.
func (s *copilotStream) Err() error {
if s.err != nil {
return s.err
}
return s.s.Err()
}
var _ Stream[*CopilotMessage] = (*copilotStream)(nil)
// CopilotStream executes a one-shot Copilot session, streaming the result.
func (c *Client) CopilotStream(ctx context.Context, params *CopilotParams) (Stream[*CopilotMessage], error) {
args := []string{"copilot", "-q", params.Prompt}
if params.Session != "" {
args = append(args, "-r", params.Session)
}
if params.FSWrite != "" {
args = append(args, "-p", "fs.write="+params.FSWrite)
}
if params.FSDelete != "" {
args = append(args, "-p", "fs.delete="+params.FSDelete)
}
s, err := c.runCommandStream(ctx, args)
if err != nil {
return nil, err
}
return &copilotStream{s: s}, nil
}
func (c Copilot) String() string {
var buf strings.Builder
for _, msg := range c {
if msg.Type == CopilotTypeMessage {
buf.WriteString(msg.Content)
}
}
return buf.String()
}
================================================
FILE: atlasexec/copilot_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec_test
import (
"context"
"fmt"
"os"
"path/filepath"
"testing"
"ariga.io/atlas/atlasexec"
"github.com/stretchr/testify/require"
)
func TestCopilot(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
c, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, "./mock-atlas.sh"))
require.NoError(t, err)
p := &atlasexec.CopilotParams{Prompt: "What is the capital of France?"}
t.Setenv("TEST_ARGS", "copilot -q "+p.Prompt)
t.Setenv("TEST_STDOUT", `{"sessionID":"id","type":"message","content":"The capital of"}
{"sessionID":"id","type":"tool_call","toolCall":{"callID":"1","function":"get_capital","arguments":"France"}}
{"sessionID":"id","type":"tool_output","toolOutput":{"callID":"1","content":"Paris"}}
{"sessionID":"id","type":"message","content":" France is Paris."}`)
copilot, err := c.Copilot(context.Background(), p)
require.NoError(t, err)
require.Equal(t, "The capital of France is Paris.", copilot.String())
p = &atlasexec.CopilotParams{Prompt: "And Germany?", Session: "id"}
t.Setenv("TEST_ARGS", fmt.Sprintf("copilot -q %s -r %s", p.Prompt, p.Session))
t.Setenv("TEST_STDOUT", `{"sessionID":"id","type":"message","content":"Berlin."}`)
copilot, err = c.Copilot(context.Background(), p)
require.NoError(t, err)
require.Equal(t, "Berlin.", copilot.String())
p = &atlasexec.CopilotParams{Prompt: "And Israel?", Session: "id", FSWrite: "*", FSDelete: "**"}
t.Setenv("TEST_ARGS", fmt.Sprintf("copilot -q %s -r %s -p fs.write=%s -p fs.delete=%s", p.Prompt, p.Session, p.FSWrite, p.FSDelete))
t.Setenv("TEST_STDOUT", `{"sessionID":"id","type":"message","content":"Jerusalem."}`)
copilot, err = c.Copilot(context.Background(), p)
require.NoError(t, err)
require.Equal(t, "Jerusalem.", copilot.String())
msgs := []string{
"Those are of course the Atlas founders.",
" CEO is Ariel Mashraki,",
" who's ability to craft clean",
" , efficient, and elegant code is legendary.",
" CTO is Rotem Tamir, also known",
" as 'THE coding and wording wizard'.",
}
var out string
for _, msg := range msgs {
out += fmt.Sprintf(`{"sessionID":"id","type":"message","content":"%s"}`+"\n", msg)
}
p = &atlasexec.CopilotParams{Prompt: "Who are the coolest people in the world?"}
t.Setenv("TEST_ARGS", "copilot -q "+p.Prompt)
t.Setenv("TEST_STDOUT", out)
s, err := c.CopilotStream(context.Background(), p)
require.NoError(t, err)
var (
m *atlasexec.CopilotMessage
i int
)
for s.Next() {
m, err = s.Current()
require.NoError(t, err)
require.Equal(t, &atlasexec.CopilotMessage{
SessionID: "id",
Type: "message",
Content: msgs[i],
}, m)
i++
}
require.NoError(t, s.Err())
}
================================================
FILE: atlasexec/internal/e2e/sqlite_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package e2etest
import (
"context"
"database/sql"
"fmt"
"log"
"os"
"testing"
"ariga.io/atlas/atlasexec"
"github.com/stretchr/testify/require"
_ "github.com/mattn/go-sqlite3"
)
func Test_SQLite(t *testing.T) {
runTestWithVersions(t, []string{"latest"}, "versioned-basic", func(t *testing.T, _ *atlasexec.Version, _ *atlasexec.WorkingDir, c *atlasexec.Client) {
url := "sqlite://file.db?_fk=1"
ctx := context.Background()
s, err := c.MigrateStatus(ctx, &atlasexec.MigrateStatusParams{
URL: url,
Env: "local",
})
require.NoError(t, err)
require.Equal(t, 1, len(s.Pending))
require.Equal(t, "20240112070806", s.Pending[0].Version)
r, err := c.MigrateApply(ctx, &atlasexec.MigrateApplyParams{
URL: url,
Env: "local",
})
require.NoError(t, err)
require.Equal(t, 1, len(r.Applied), "Should be one migration applied")
require.Equal(t, "20240112070806", r.Applied[0].Version, "Should be the correct migration applied")
// Apply again, should be a no-op.
r, err = c.MigrateApply(ctx, &atlasexec.MigrateApplyParams{
URL: url,
Env: "local",
})
require.NoError(t, err, "Should be no error")
require.Equal(t, 0, len(r.Applied), "Should be no migrations applied")
})
}
func Test_PostgreSQL(t *testing.T) {
u := os.Getenv("ATLASEXEC_E2ETEST_POSTGRES_URL")
if u == "" {
t.Skip("ATLASEXEC_E2ETEST_POSTGRES_URL not set")
}
runTestWithVersions(t, []string{"latest"}, "versioned-basic", func(t *testing.T, _ *atlasexec.Version, _ *atlasexec.WorkingDir, c *atlasexec.Client) {
url := u
ctx := context.Background()
s, err := c.MigrateStatus(ctx, &atlasexec.MigrateStatusParams{
URL: url,
Env: "local",
})
require.NoError(t, err)
require.Equal(t, 1, len(s.Pending))
require.Equal(t, "20240112070806", s.Pending[0].Version)
r, err := c.MigrateApply(ctx, &atlasexec.MigrateApplyParams{
URL: url,
Env: "local",
})
require.NoError(t, err)
require.Equal(t, 1, len(r.Applied), "Should be one migration applied")
require.Equal(t, "20240112070806", r.Applied[0].Version, "Should be the correct migration applied")
// Apply again, should be a no-op.
r, err = c.MigrateApply(ctx, &atlasexec.MigrateApplyParams{
URL: url,
Env: "local",
})
require.NoError(t, err, "Should be no error")
require.Equal(t, 0, len(r.Applied), "Should be no migrations applied")
})
}
func Test_MultiTenants(t *testing.T) {
t.Setenv("ATLASEXEC_E2ETEST_ATLAS_PATH", "atlas")
runTestWithVersions(t, []string{"latest"}, "multi-tenants", func(t *testing.T, _ *atlasexec.Version, wd *atlasexec.WorkingDir, c *atlasexec.Client) {
ctx := context.Background()
r, err := c.MigrateApplySlice(ctx, &atlasexec.MigrateApplyParams{
Env: "local",
Amount: 1, // Only apply one migration.
})
require.NoError(t, err)
require.Len(t, r, 2, "Should be two tenants")
require.Equal(t, 1, len(r[0].Applied), "Should be one migration applied")
require.Equal(t, "20240112070806", r[0].Applied[0].Version, "Should be the correct migration applied")
// Insert some data to the second tenant to make the migration fail.
db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s?_fk=1", wd.Path("foo.db")))
if err != nil {
log.Fatalf("failed opening db: %s", err)
}
_, err = db.Exec("INSERT INTO t1(c1) VALUES (1),(1),(1)")
require.NoError(t, err)
// Apply again, should be one successful and one failed migration.
_, err = c.MigrateApplySlice(ctx, &atlasexec.MigrateApplyParams{
Env: "local",
})
require.ErrorContains(t, err, "UNIQUE constraint failed", "Should be error")
mae, ok := err.(*atlasexec.MigrateApplyError)
require.True(t, ok, "Should be a MigrateApplyError")
require.Len(t, mae.Result, 2, "Should be two reports")
require.Equal(t, 1, len(mae.Result[0].Applied), "Should be one migration applied")
require.Equal(t, "20240116003831", mae.Result[0].Applied[0].Version, "Should be the correct migration applied")
require.Equal(t, 1, len(mae.Result[1].Applied), "Should be one migration applied")
require.Contains(t, mae.Result[1].Error, "UNIQUE constraint failed", "Should be the correct error")
// Apply again, should be one successful and one failed migration.
_, err = c.MigrateApplySlice(ctx, &atlasexec.MigrateApplyParams{
Env: "local",
})
require.ErrorContains(t, err, "UNIQUE constraint failed", "Should be error")
mae, ok = err.(*atlasexec.MigrateApplyError)
require.True(t, ok, "Should be a MigrateApplyError")
require.Len(t, mae.Result, 2, "Should be two reports")
require.Equal(t, 0, len(mae.Result[0].Applied), "Should be no migrations applied")
require.Equal(t, 1, len(mae.Result[1].Applied), "Should be one tried to apply")
require.Contains(t, mae.Result[1].Error, "UNIQUE constraint failed", "Should be the correct error")
})
}
func Test_SchemaPlan(t *testing.T) {
runTestWithVersions(t, []string{"latest"}, "schema-plan", func(t *testing.T, _ *atlasexec.Version, _ *atlasexec.WorkingDir, c *atlasexec.Client) {
ctx := context.Background()
plan, err := c.SchemaPlan(ctx, &atlasexec.SchemaPlanParams{
From: []string{"file://schema-1.lt.hcl"},
To: []string{"file://schema-2.lt.hcl"},
DevURL: "sqlite://:memory:?_fk=1",
DryRun: true,
})
require.NoError(t, err)
f := plan.File
require.NotNil(t, f, "Should have a file")
require.Equal(t, "-- Add column \"c2\" to table: \"t1\"\nALTER TABLE `t1` ADD COLUMN `c2` text NOT NULL;\n", f.Migration, "Should be the correct migration")
require.Empty(t, f.URL, "Should be no URL")
})
runTestWithVersions(t, []string{"latest"}, "schema-plan", func(t *testing.T, _ *atlasexec.Version, _ *atlasexec.WorkingDir, c *atlasexec.Client) {
ctx := context.Background()
plan, err := c.SchemaPlan(ctx, &atlasexec.SchemaPlanParams{
From: []string{"file://schema-1.lt.hcl"},
To: []string{"file://schema-2.lt.hcl"},
DevURL: "sqlite://:memory:?_fk=1",
Save: true,
})
require.NoError(t, err)
f := plan.File
require.NotNil(t, f, "Should have a file")
require.Equal(t, "-- Add column \"c2\" to table: \"t1\"\nALTER TABLE `t1` ADD COLUMN `c2` text NOT NULL;\n", f.Migration, "Should be the correct migration")
require.Regexp(t, "^file://\\d{14}\\.plan\\.hcl$", f.URL, "Should be an URL to a file")
})
}
================================================
FILE: atlasexec/internal/e2e/testdata/multi-tenants/atlas.hcl
================================================
env {
for_each = toset([
"sqlite://bar.db?_fk=1",
"sqlite://foo.db?_fk=1",
])
name = atlas.env
url = each.value
migration {
dir = "file://migrations"
}
}
================================================
FILE: atlasexec/internal/e2e/testdata/multi-tenants/migrations/20240112070806.sql
================================================
CREATE TABLE t1(c1 int);
================================================
FILE: atlasexec/internal/e2e/testdata/multi-tenants/migrations/20240116003831.sql
================================================
CREATE UNIQUE INDEX c1_unique ON t1(c1);
================================================
FILE: atlasexec/internal/e2e/testdata/multi-tenants/migrations/atlas.sum
================================================
h1:S0UEXIKYA1mHhjFJbnzZh7bzeb42+5KM4HLzVlGuE4Q=
20240112070806.sql h1:nhoPxDs1H3UH6aEpy1qJ6Bj6zbFRt61sB4ndi0sx7zw=
20240116003831.sql h1:X3xnvEuBDK23s+re/ZYMdx/Ian+WhvzLgeJBN/2TJrA=
================================================
FILE: atlasexec/internal/e2e/testdata/schema-plan/schema-1.lt.hcl
================================================
schema "public" {
comment = "This is a test schema"
}
table "t1" {
schema = schema.public
column "c1" {
type = bigint
}
}
================================================
FILE: atlasexec/internal/e2e/testdata/schema-plan/schema-2.lt.hcl
================================================
schema "public" {
comment = "This is a test schema"
}
table "t1" {
schema = schema.public
column "c1" {
type = bigint
}
column "c2" {
type = text
}
}
================================================
FILE: atlasexec/internal/e2e/testdata/versioned-basic/atlas.hcl
================================================
env "local" {
migration {
dir = "file://migrations"
}
}
================================================
FILE: atlasexec/internal/e2e/testdata/versioned-basic/migrations/20240112070806.sql
================================================
CREATE TABLE t1(c1 int);
================================================
FILE: atlasexec/internal/e2e/testdata/versioned-basic/migrations/atlas.sum
================================================
h1:vefBQWShy7/4OI7C1NqFH9y2PtGtOUS5zFQ1492XitE=
20240112070806.sql h1:nhoPxDs1H3UH6aEpy1qJ6Bj6zbFRt61sB4ndi0sx7zw=
================================================
FILE: atlasexec/internal/e2e/util_e2e.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package e2etest
import (
"context"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"path/filepath"
"testing"
"ariga.io/atlas/atlasexec"
)
const testFixtureDir = "testdata"
func runTestWithVersions(t *testing.T, versions []string, fixtureName string, cb func(t *testing.T, ver *atlasexec.Version, wd *atlasexec.WorkingDir, tf *atlasexec.Client)) {
if os.Getenv("ATLASEXEC_E2ETEST") == "" {
t.Skip("ATLASEXEC_E2ETEST not set")
}
t.Helper()
alreadyRunVersions := map[string]bool{}
for _, av := range versions {
t.Run(fmt.Sprintf("%s-%s", fixtureName, av), func(t *testing.T) {
if alreadyRunVersions[av] {
t.Skipf("already run version %q", av)
}
alreadyRunVersions[av] = true
var execPath string
if localBinPath := os.Getenv("ATLASEXEC_E2ETEST_ATLAS_PATH"); localBinPath != "" {
execPath = localBinPath
} else {
execPath = downloadAtlas(t, av)
if err := os.Chmod(execPath, 0755); err != nil {
t.Fatalf("unable to make atlas executable: %s", err)
}
}
c, err := atlasexec.NewClient("", execPath)
if err != nil {
t.Fatal(err)
}
// TODO: Check that the version is the same as the one we expect.
runningVersion, err := c.Version(context.Background())
if err != nil {
t.Fatalf("unable to determine running version (expected %q): %s", av, err)
}
wd, err := atlasexec.NewWorkingDir()
if err != nil {
t.Fatal(err)
}
defer wd.Close()
if fixtureName != "" {
err := wd.CopyFS("", os.DirFS(filepath.Join(testFixtureDir, fixtureName)))
if err != nil {
t.Fatalf("error copying config file into test dir: %s", err)
}
}
err = c.WithWorkDir(wd.Path(), func(c *atlasexec.Client) (err error) {
defer func() {
if r := recover(); r != nil {
var ok bool
if err, ok = r.(error); !ok {
err = fmt.Errorf("run test failure: %v", r)
}
}
}()
cb(t, runningVersion, wd, c)
return nil
})
if err != nil {
t.Fatal(err)
}
})
}
}
func downloadAtlas(t *testing.T, version string) string {
t.Helper()
c := http.DefaultClient
req, err := http.NewRequest(http.MethodGet, "https://atlasgo.sh?test=1", nil)
if err != nil {
t.Fatal(err)
}
req.Header.Set("User-Agent", "AtlasExec/Integration-Test")
res, err := c.Do(req)
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
t.Fatalf("unexpected status code: %d", res.StatusCode)
}
path := filepath.Join(t.TempDir(), "installer.sh")
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
if err != nil {
t.Fatal(err)
}
if _, err = io.Copy(f, res.Body); err != nil {
f.Close()
t.Fatal(err)
} else if err = f.Close(); err != nil {
t.Fatal(err)
}
atlasBin := filepath.Join(t.TempDir(), "atlas")
cmd := exec.Command(path,
"--user-agent", "AtlasExec/Integration-Test",
"--output", atlasBin,
"--no-install",
)
cmd.Env = append(os.Environ(), fmt.Sprintf("ATLAS_VERSION=%s", version))
if testing.Verbose() {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}
if err = cmd.Run(); err != nil {
t.Fatal(err)
}
return atlasBin
}
================================================
FILE: atlasexec/mock-atlas.sh
================================================
#!/bin/bash
# TEST_BATCH provide the directory contains all
# outputs for multiple runs. The path should be absolute
# or related to current working directory.
if [[ "$TEST_BATCH" != "" ]]; then
COUNTER_FILE=$TEST_BATCH/counter
COUNTER=$(cat $COUNTER_FILE 2>/dev/null)
COUNTER=$((COUNTER+1))
DIR_CUR="$TEST_BATCH/$COUNTER"
if [ ! -d "$DIR_CUR" ]; then
>&2 echo -n "$DIR_CUR does not exist, quitting..."
exit 1
fi
# Save counter for the next runs
echo -n $COUNTER > $COUNTER_FILE
if [ -f "$DIR_CUR/args" ]; then
TEST_ARGS=$(cat $DIR_CUR/args)
fi
if [ -f "$DIR_CUR/stderr" ]; then
TEST_STDERR=$(cat $DIR_CUR/stderr)
fi
if [ -f "$DIR_CUR/stdout" ]; then
TEST_STDOUT=$(cat $DIR_CUR/stdout)
fi
fi
if [[ "$TEST_ARGS" != "$@" ]]; then
>&2 echo "Receive unexpected args: $@"
exit 1
fi
if [[ "$TEST_STDOUT" != "" ]]; then
printf "%s" "$TEST_STDOUT"
if [[ "$TEST_STDERR" == "" ]]; then
# `migrate down` and `migrate lint` commands print result to stdout
# but the error code is set to 1.
exit ${TEST_EXIT_CODE:-0} # No stderr
fi
# In some cases, Atlas will write the error in stderr
# when if the command is partially successful.
# eg. Run the apply commands with multiple environments.
>&2 echo -n $TEST_STDERR
exit 1
fi
TEST_STDERR="${TEST_STDERR:-Missing stderr either stdout input for the test}"
>&2 echo -n $TEST_STDERR
exit 1
================================================
FILE: atlasexec/testdata/broken/20231029112426.sql
================================================
broken;
================================================
FILE: atlasexec/testdata/broken/atlas.sum
================================================
h1:Enr95HgKxQs2iSsOANpqDUOaHc6eZeQ+ak0ZF2wjmZE=
20231029112426.sql h1:lHLnIyWaiYac90Ad0I1SOsPxvQng3tGlq++/8RkpJaI=
================================================
FILE: atlasexec/testdata/migrations/20230727105553_init.sql
================================================
CREATE TABLE t1 ( c1 int );
================================================
FILE: atlasexec/testdata/migrations/20230727105615_t2.sql
================================================
CREATE TABLE t2 ( c1 int, c2 text );
================================================
FILE: atlasexec/testdata/migrations/20230926085734_destructive-change.sql
================================================
DROP TABLE t2;
================================================
FILE: atlasexec/testdata/migrations/atlas.sum
================================================
h1:hnQZfRcN6sV+y+0YePtkLazMy+Ty3lhyGv69ixeYoXc=
20230727105553_init.sql h1:jxgvnWO6tZD3lSPpH1ao5E/6VjapP7iwvBCUJ6aez58=
20230727105615_t2.sql h1:UvzeoFxe90Y/7b21ziwg6pPzWJQSV7LeYwJl8J63lMU=
20230926085734_destructive-change.sql h1:Gf/bSvUkfqHr/MEXKCxdGu2YvG8zwe4ER5TW8T/laA0=
================================================
FILE: atlasexec/working_dir.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec
import (
"errors"
"io"
"io/fs"
"os"
"os/exec"
"path/filepath"
"ariga.io/atlas/sql/migrate"
)
type (
// WorkingDir is a temporary directory with a copy of the files from dir.
// It can be used to run commands in the temporary directory.
// The temporary directory is removed when Close is called.
WorkingDir struct {
dir string
}
// Option is a function that modifies a ContextExecer.
Option func(ce *WorkingDir) error
)
// WithAtlasHCLString creates the atlas.hcl file with the given string.
func WithAtlasHCLString(s string) Option {
return WithAtlasHCL(func(w io.Writer) error {
_, err := w.Write([]byte(s))
return err
})
}
// WithAtlasHCLPath creates the atlas.hcl file by copying the file at the given path.
func WithAtlasHCLPath(path string) Option {
return WithAtlasHCL(func(w io.Writer) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(w, f)
return err
})
}
// WithAtlasHCL accept a function to create the atlas.hcl file.
func WithAtlasHCL(fn func(w io.Writer) error) Option {
return func(ce *WorkingDir) error {
return ce.CreateFile("atlas.hcl", fn)
}
}
// WithMigrations copies all files from dir to the migrations directory.
// If dir is nil, no files are copied.
func WithMigrations(dir fs.FS) Option {
return func(ce *WorkingDir) error {
if dir == nil {
return nil
}
return ce.CopyFS("migrations", dir)
}
}
// NewWorkingDir creates a new ContextExecer.
// It creates a temporary directory and copies all files from dir to the temporary directory.
// The atlasHCL function is called with a writer to create the atlas.hcl file.
// If atlasHCL is nil, no atlas.hcl file is created.
func NewWorkingDir(opts ...Option) (*WorkingDir, error) {
tmpDir, err := os.MkdirTemp("", "atlasexec-*")
if err != nil {
if err2 := os.RemoveAll(tmpDir); err2 != nil {
err = errors.Join(err, err2)
}
return nil, err
}
c := &WorkingDir{dir: tmpDir}
for _, opt := range opts {
if err := opt(c); err != nil {
return nil, err
}
}
return c, nil
}
// Close removes the temporary directory.
func (ce *WorkingDir) Close() error {
return os.RemoveAll(ce.dir)
}
// DirFS returns a fs.FS for the temporary directory.
func (ce *WorkingDir) DirFS() fs.FS {
return os.DirFS(ce.dir)
}
// Dir returns the path to the temporary directory.
func (ce *WorkingDir) Path(elem ...string) string {
if len(elem) == 0 {
return ce.dir
}
return filepath.Join(append([]string{ce.dir}, elem...)...)
}
// RunCommand runs the command in the temporary directory.
func (ce *WorkingDir) RunCommand(cmd *exec.Cmd) error {
// Restore the current directory after the command is run.
defer func(d string) { cmd.Dir = d }(cmd.Dir)
cmd.Dir = ce.dir
return cmd.Run()
}
// WriteFile writes the file to the temporary directory.
func (ce *WorkingDir) WriteFile(name string, data []byte) (string, error) {
err := ce.CreateFile(name, func(w io.Writer) (err error) {
_, err = w.Write(data)
return err
})
if err != nil {
return "", err
}
return ce.Path(name), err
}
// CreateFile creates the file in the temporary directory.
func (ce *WorkingDir) CreateFile(name string, fn func(w io.Writer) error) error {
f, err := os.Create(ce.Path(name))
if err != nil {
return err
}
if err := fn(f); err != nil {
if err2 := f.Close(); err2 != nil {
err = errors.Join(err, err2)
}
return err
}
return f.Close()
}
// CopyFS copies all files from source FileSystem to the destination directory
// in the temporary directory.
// If source is nil, an error is returned.
func (ce *WorkingDir) CopyFS(name string, src fs.FS) error {
dst := ce.Path(name)
// Ensure destination directory exists.
if err := os.MkdirAll(dst, 0700); err != nil {
return err
}
switch dir := src.(type) {
case nil:
return errors.New("atlasexec: source is nil")
case migrate.Dir:
// The migrate.MemDir doesn't 100% compatible with fs.FS.
// It returns fs.ErrNotExist error when open "." directory.
// So, we need to handle it separately using the Files method.
files, err := dir.Files()
if err != nil {
return err
}
for _, f := range files {
name := filepath.Join(dst, f.Name())
if err := os.WriteFile(name, f.Bytes(), 0644); err != nil { //nolint:gosec
return err
}
}
// If the atlas.sum file exists, copy it to the destination directory.
if hf, err := dir.Open(migrate.HashFileName); err == nil {
data, err := io.ReadAll(hf)
if err != nil {
return err
}
name := filepath.Join(dst, migrate.HashFileName)
if err := os.WriteFile(name, data, 0644); err != nil { //nolint:gosec
return err
}
}
return nil
default:
return fs.WalkDir(dir, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil || path == "." {
return err
}
name := filepath.Join(dst, path)
if d.IsDir() {
return os.Mkdir(name, 0700)
}
data, err := fs.ReadFile(dir, path)
if err != nil {
return err
}
return os.WriteFile(name, data, 0644) //nolint:gosec
})
}
}
================================================
FILE: atlasexec/working_dir_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package atlasexec
import (
"bytes"
"io"
"os"
"os/exec"
"path/filepath"
"testing"
"testing/fstest"
"text/template"
"ariga.io/atlas/sql/migrate"
"github.com/stretchr/testify/require"
)
func TestContextExecer(t *testing.T) {
src := fstest.MapFS{
"bar": &fstest.MapFile{Data: []byte("bar-content")},
}
ce, err := NewWorkingDir()
checkFileContent := func(t *testing.T, name, expected string) {
t.Helper()
full := filepath.Join(ce.dir, name)
require.FileExists(t, full, "The file %q should exist", name)
actual, err := os.ReadFile(full)
require.NoError(t, err)
require.Equal(t, expected, string(actual), "The file %q should have the expected content", name)
}
require.NoError(t, err)
require.DirExists(t, ce.dir, "The temporary directory should exist")
require.NoFileExists(t, filepath.Join(ce.dir, "atlas.hcl"), "The file atlas.hcl should not exist")
require.NoError(t, ce.Close())
// Test WithMigrations.
ce, err = NewWorkingDir(WithMigrations(src))
require.NoError(t, err)
checkFileContent(t, filepath.Join("migrations", "bar"), "bar-content")
require.NoError(t, ce.Close())
// Test WithMigrations - MemDir.
dir := &migrate.MemDir{}
require.NoError(t, dir.WriteFile("1.sql", []byte("-- only .sql files are copied\nmem-content")))
require.NoError(t, dir.WriteFile(migrate.HashFileName, []byte("-- And the atlas.sum")))
ce, err = NewWorkingDir(WithMigrations(dir))
require.NoError(t, err)
checkFileContent(t, filepath.Join("migrations", "1.sql"), "-- only .sql files are copied\nmem-content")
checkFileContent(t, filepath.Join("migrations", migrate.HashFileName), "-- And the atlas.sum")
require.NoError(t, ce.Close())
// Test WithAtlasHCL.
ce, err = NewWorkingDir(
WithAtlasHCL(func(w io.Writer) error {
return template.Must(template.New("").Parse(`{{ .foo }} & {{ .bar }}`)).
Execute(w, map[string]any{
"foo": "foo",
"bar": "bar",
})
}),
WithMigrations(src),
)
require.NoError(t, err)
require.DirExists(t, ce.dir, "tmpDir")
checkFileContent(t, filepath.Join("migrations", "bar"), "bar-content")
checkFileContent(t, "atlas.hcl", "foo & bar")
// Test WriteFile.
_, err = ce.WriteFile(filepath.Join("migrations", "foo"), []byte("foo-content"))
require.NoError(t, err)
checkFileContent(t, filepath.Join("migrations", "foo"), "foo-content")
// Test RunCommand.
buf := &bytes.Buffer{}
cmd := exec.Command("ls")
cmd.Dir = "fake-dir"
cmd.Stdout = buf
require.NoError(t, ce.RunCommand(cmd))
require.Equal(t, "fake-dir", cmd.Dir)
require.Equal(t, "atlas.hcl\nmigrations\n", buf.String())
require.NoError(t, ce.Close())
}
func TestMaintainOriginalWorkingDir(t *testing.T) {
dir := t.TempDir()
c, err := NewClient(dir, "atlas")
require.NoError(t, err)
require.Equal(t, dir, c.workingDir)
require.NoError(t, c.WithWorkDir("bar", func(c *Client) error {
require.Equal(t, "bar", c.workingDir)
return nil
}))
require.Equal(t, dir, c.workingDir, "The working directory should not be changed")
}
================================================
FILE: cmd/atlas/go.mod
================================================
module ariga.io/atlas/cmd/atlas
go 1.24.13
replace ariga.io/atlas => ../..
require (
ariga.io/atlas v0.32.1-0.20250325101103-175b25e1c1b9
entgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4
github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1
github.com/antlr4-go/antlr/v4 v4.13.0
github.com/aws/aws-sdk-go-v2/config v1.29.17
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16
github.com/chzyer/readline v1.5.1
github.com/fatih/color v1.16.0
github.com/go-sql-driver/mysql v1.9.3
github.com/google/uuid v1.6.0
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/hashicorp/hcl/v2 v2.18.1
github.com/lib/pq v1.10.9
github.com/mattn/go-isatty v0.0.20
github.com/mattn/go-sqlite3 v1.14.28
github.com/mitchellh/go-homedir v1.1.0
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.11.1
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d
github.com/vektah/gqlparser/v2 v2.5.16
github.com/zclconf/go-cty v1.14.4
gocloud.dev v0.43.0
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
golang.org/x/mod v0.26.0
golang.org/x/oauth2 v0.30.0
google.golang.org/api v0.242.0
)
require (
cloud.google.com/go/auth v0.16.3 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.7.0 // indirect
cloud.google.com/go/iam v1.5.2 // indirect
cloud.google.com/go/longrunning v0.6.7 // indirect
cloud.google.com/go/secretmanager v1.15.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/agext/levenshtein v1.2.3 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/aws/aws-sdk-go v1.55.7 // indirect
github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
github.com/aws/smithy-go v1.22.4 // indirect
github.com/bmatcuk/doublestar v1.3.4 // indirect
github.com/coder/websocket v1.8.12 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/wire v0.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/zclconf/go-cty-yaml v1.1.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/time v0.12.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 // indirect
google.golang.org/grpc v1.73.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
================================================
FILE: cmd/atlas/go.sum
================================================
cloud.google.com/go v0.121.4 h1:cVvUiY0sX0xwyxPwdSU2KsF9knOVmtRyAMt8xou0iTs=
cloud.google.com/go v0.121.4/go.mod h1:XEBchUiHFJbz4lKBZwYBDHV/rSyfFktk737TLDU089s=
cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc=
cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA=
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.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
cloud.google.com/go/kms v1.22.0 h1:dBRIj7+GDeeEvatJeTB19oYZNV0aj6wEqSIT/7gLqtk=
cloud.google.com/go/kms v1.22.0/go.mod h1:U7mf8Sva5jpOb4bxYZdtw/9zsbIjrklYwPcvMk34AL8=
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
cloud.google.com/go/secretmanager v1.15.0 h1:RtkCMgTpaBMbzozcRUGfZe46jb9a3qh5EdEtVRUATF8=
cloud.google.com/go/secretmanager v1.15.0/go.mod h1:1hQSAhKK7FldiYw//wbR/XPfPc08eQ81oBsnRUHEvUc=
entgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4 h1:d7UZAvQCnOp1PyiHAWkPCXBEPW3tVjraiK/RZlsW0XY=
entgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4/go.mod h1:zTzLmWtPvGpmSwtkaayM2cm5m819NdM7z7tYPq3vN0U=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1 h1:LejjvYg4tCW5HO7q/1nzPrprh47oUD9OUySQ29pDp5c=
github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1/go.mod h1:cnC/60IoLiDM0GhdKYJ6oO7AwpZe1IQfPnSKlAURgHw=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=
github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac=
github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0=
github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=
github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0=
github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8=
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0=
github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8=
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16 h1:j+YO7Khxpk73ESxUpheUSw91qT42+LqNZiEjul1Dmnk=
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16/go.mod h1:laSv+AlZPuT/bpJQ2Xspq/oDKhB/XZLohISGTKU7DOg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7 h1:d+mnMa4JbJlooSbYQfrJpit/YINaB30JEVgrhtjZneA=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7/go.mod h1:1X1NotbcGHH7PCQJ98PsExSxsJj/VWzz8MfFz43+02M=
github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1 h1:OwMzNDe5VVTXD4kGmeK/FtqAITiV8Mw4TCa8IyNO0as=
github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1/go.mod h1:IyVabkWrs8SNdOEZLyFFcW9bUltV4G6OQS0s6H20PHg=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E=
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0=
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w=
github.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
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-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
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.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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/go-replayers/grpcreplay v1.3.0 h1:1Keyy0m1sIpqstQmgz307zhiJ1pV4uIlFds5weTmxbo=
github.com/google/go-replayers/grpcreplay v1.3.0/go.mod h1:v6NgKtkijC0d3e3RW8il6Sy5sqRVUwoQa4mHOGEy8DI=
github.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk=
github.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy+tME4bwyqPcwWbNlUI1Mcg=
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
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/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
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/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/hcl/v2 v2.18.1 h1:6nxnOJFku1EuSawSD81fuviYUV8DxFr3fp2dUi3ZYSo=
github.com/hashicorp/hcl/v2 v2.18.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
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/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
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.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU=
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s=
github.com/vektah/gqlparser/v2 v2.5.16 h1:1gcmLTvs3JLKXckwCwlUagVn/IlV2bwqle0vJ0vy5p8=
github.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0=
github.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 h1:rbRJ8BBoVMsQShESYZ0FkvcITu8X8QNwJogcLUmDNNw=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0/go.mod h1:ru6KHrNtNHxM4nD/vd6QrLVWgKhxPYgblq4VAtNawTQ=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
gocloud.dev v0.43.0 h1:aW3eq4RMyehbJ54PMsh4hsp7iX8cO/98ZRzJJOzN/5M=
gocloud.dev v0.43.0/go.mod h1:eD8rkg7LhKUHrzkEdLTZ+Ty/vgPHPCd+yMQdfelQVu4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg=
google.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 h1:Nt6z9UHqSlIdIGJdz6KhTIs2VRx/iOsA5iE8bmQNcxs=
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79/go.mod h1:kTmlBHMPqR5uCZPBvwa2B18mvubkjyY3CRLI0c6fj0s=
google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 h1:iOye66xuaAK0WnkPuhQPUFy8eJcmwUXqGGP3om6IxX8=
google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79/go.mod h1:HKJDgKsFUnv5VAGeQjz8kxcgDP0HoE0iZNp0OdZNlhE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 h1:1ZwqphdOdWYXsUHgMpU/101nCtf/kSp9hOrcvFsnl10=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
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.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
================================================
FILE: cmd/atlas/internal/cloudapi/client.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cloudapi
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"runtime"
"slices"
"strings"
"testing"
"time"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/sqlclient"
"github.com/hashicorp/go-retryablehttp"
"github.com/vektah/gqlparser/v2/gqlerror"
)
const (
// defaultURL for Atlas Cloud.
defaultURL = "https://api.atlasgo.cloud/query"
// DefaultProjectName is the default name for projects.
DefaultProjectName = "default"
// DefaultDirName is the default directory for reporting
// if no directory was specified by the user.
DefaultDirName = ".atlas"
)
// Client is a client for the Atlas Cloud API.
type Client struct {
client *retryablehttp.Client
endpoint string
}
// New creates a new Client for the Atlas Cloud API.
func New(endpoint, token string) *Client {
if endpoint == "" {
endpoint = defaultURL
}
var (
client = retryablehttp.NewClient()
transport = client.HTTPClient.Transport
)
client.HTTPClient.Timeout = time.Second * 30
client.ErrorHandler = func(res *http.Response, err error, _ int) (*http.Response, error) {
return res, err // Let Client.post handle the error.
}
client.HTTPClient.Transport = &roundTripper{
token: token,
base: transport,
extraHeaders: make(map[string]string),
}
// Disable logging until "ATLAS_DEBUG" option will be added.
client.Logger = nil
// Keep retry short for unit/integration tests.
if testing.Testing() || testingURL(endpoint) {
client.HTTPClient.Timeout = 0
client.RetryWaitMin, client.RetryWaitMax = 0, time.Microsecond
}
return &Client{
endpoint: endpoint,
client: client,
}
}
type clientCtxKey struct{}
// NewContext returns a new context with the given Client attached.
func NewContext(parent context.Context, c *Client) context.Context {
return context.WithValue(parent, clientCtxKey{}, c)
}
// FromContext returns a Client stored inside a context, or nil if there isn't one.
func FromContext(ctx context.Context) *Client {
c, _ := ctx.Value(clientCtxKey{}).(*Client)
return c
}
// DirInput is the input type for retrieving a single directory.
type DirInput struct {
Slug string `json:"slug,omitempty"`
Name string `json:"name,omitempty"`
Tag string `json:"tag,omitempty"`
}
// Dir retrieves a directory from the Atlas Cloud API.
func (c *Client) Dir(ctx context.Context, input DirInput) (migrate.Dir, error) {
var (
payload struct {
Dir struct {
Content []byte `json:"content"`
} `json:"dirState"`
}
query = `
query dirState($input: DirStateInput!) {
dirState(input: $input) {
content
}
}`
vars = struct {
Input DirInput `json:"input"`
}{
Input: input,
}
)
if err := c.post(ctx, query, vars, &payload); err != nil {
return nil, err
}
return migrate.UnarchiveDir(payload.Dir.Content)
}
type (
// DeployContextInput is an input type for describing the context in which
// `migrate-apply` was used. For example, a GitHub Action with version v1.2.3
DeployContextInput struct {
TriggerType string `json:"triggerType,omitempty"`
TriggerVersion string `json:"triggerVersion,omitempty"`
}
// ReportMigrationSetInput represents the input type for reporting a set of migration deployments.
ReportMigrationSetInput struct {
ID string `json:"id"`
Planned int `json:"planned"`
StartTime time.Time `json:"startTime"`
EndTime time.Time `json:"endTime"`
Error *string `json:"error,omitempty"`
Log []ReportStep `json:"log,omitempty"`
Completed []ReportMigrationInput `json:"completed,omitempty"`
Context *DeployContextInput `json:"context,omitempty"`
}
// ReportMigrationInput represents an input type for reporting a migration deployments.
ReportMigrationInput struct {
ProjectName string `json:"projectName"`
EnvName string `json:"envName"`
DirName string `json:"dirName"`
AtlasVersion string `json:"atlasVersion"`
Target DeployedTargetInput `json:"target"`
StartTime time.Time `json:"startTime"`
EndTime time.Time `json:"endTime"`
FromVersion string `json:"fromVersion"`
ToVersion string `json:"toVersion"`
CurrentVersion string `json:"currentVersion"`
Error *string `json:"error,omitempty"`
Files []DeployedFileInput `json:"files"`
Log string `json:"log"`
Context *DeployContextInput `json:"context,omitempty"`
DryRun bool `json:"dryRun,omitempty"`
}
// DeployedTargetInput represents the input type for a deployed target.
DeployedTargetInput struct {
ID string `json:"id"`
Schema string `json:"schema"`
URL string `json:"url"` // URL string without userinfo.
}
// DeployedFileInput represents the input type for a deployed file.
DeployedFileInput struct {
Name string `json:"name"`
Content string `json:"content"`
StartTime time.Time `json:"startTime"`
EndTime time.Time `json:"endTime"`
Skipped int `json:"skipped"`
Applied int `json:"applied"`
Checks []FileChecksInput `json:"checks"`
Error *StmtErrorInput `json:"error,omitempty"`
}
// FileChecksInput represents the input type for a file checks.
FileChecksInput struct {
Name string `json:"name"`
Start time.Time `json:"start"`
End time.Time `json:"end"`
Checks []CheckStmtInput `json:"checks"`
Error *StmtErrorInput `json:"error,omitempty"`
}
// CheckStmtInput represents the input type for a statement check.
CheckStmtInput struct {
Stmt string `json:"stmt"`
Error *string `json:"error,omitempty"`
}
// StmtErrorInput represents the input type for a statement error.
StmtErrorInput struct {
Stmt string `json:"stmt"`
Text string `json:"text"`
}
// ReportStep is top-level step in a report.
ReportStep struct {
Text string `json:"text"`
StartTime time.Time `json:"startTime"`
EndTime time.Time `json:"endTime"`
Error bool `json:"error,omitempty"`
Log []ReportStepLog `json:"log,omitempty"`
}
// ReportStepLog is a log entry in a step.
ReportStepLog struct {
Text string `json:"text,omitempty"`
Children []ReportStepLog `json:"children,omitempty"`
}
)
// ReportMigrationSet reports a set of migration deployments to the Atlas Cloud API.
func (c *Client) ReportMigrationSet(ctx context.Context, input ReportMigrationSetInput) (string, error) {
var (
payload struct {
ReportMigrationSet struct {
URL string `json:"url"`
} `json:"reportMigrationSet"`
}
query = `
mutation ReportMigrationSet($input: ReportMigrationSetInput!) {
reportMigrationSet(input: $input) {
url
}
}`
vars = struct {
Input ReportMigrationSetInput `json:"input"`
}{
Input: input,
}
)
if err := c.post(ctx, query, vars, &payload); err != nil {
return "", err
}
return payload.ReportMigrationSet.URL, nil
}
// ReportMigration reports a migration deployment to the Atlas Cloud API.
func (c *Client) ReportMigration(ctx context.Context, input ReportMigrationInput) (string, error) {
var (
payload struct {
ReportMigration struct {
URL string `json:"url"`
} `json:"reportMigration"`
}
query = `
mutation ReportMigration($input: ReportMigrationInput!) {
reportMigration(input: $input) {
url
}
}`
vars = struct {
Input ReportMigrationInput `json:"input"`
}{
Input: input,
}
)
if err := c.post(ctx, query, vars, &payload); err != nil {
return "", err
}
return payload.ReportMigration.URL, nil
}
// ErrUnauthorized is returned when the server returns a 401 status code.
var ErrUnauthorized = errors.New(http.StatusText(http.StatusUnauthorized))
func (c *Client) post(ctx context.Context, query string, vars, data any) error {
body, err := json.Marshal(struct {
Query string `json:"query"`
Variables any `json:"variables,omitempty"`
}{
Query: query,
Variables: vars,
})
if err != nil {
return err
}
req, err := retryablehttp.NewRequestWithContext(ctx, http.MethodPost, c.endpoint, bytes.NewReader(body))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
res, err := c.client.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
switch {
case res.StatusCode == http.StatusUnauthorized:
return ErrUnauthorized
case res.StatusCode != http.StatusOK:
buf, err := io.ReadAll(io.LimitReader(res.Body, 1<<20))
if err != nil {
return &HTTPError{StatusCode: res.StatusCode, Message: err.Error()}
}
var v struct {
Errors errlist `json:"errors,omitempty"`
}
if err := json.Unmarshal(buf, &v); err != nil || len(v.Errors) == 0 {
// If the error is not a GraphQL error, return the message as is.
return &HTTPError{StatusCode: res.StatusCode, Message: string(bytes.TrimSpace(buf))}
}
return v.Errors
}
var scan = struct {
Data any `json:"data"`
Errors errlist `json:"errors,omitempty"`
}{
Data: data,
}
if err := json.NewDecoder(res.Body).Decode(&scan); err != nil && !errors.Is(err, io.EOF) {
return fmt.Errorf("decoding response: %w", err)
}
if len(scan.Errors) > 0 {
return scan.Errors
}
return nil
}
// AddHeader adds a header to the client requests.
func (c *Client) AddHeader(key, value string) {
rt, ok := c.client.HTTPClient.Transport.(*roundTripper)
if !ok {
return
}
rt.extraHeaders[key] = value
}
type (
// errlist wraps the gqlerror.List to print errors without
// extra newlines and prefix info added.
errlist gqlerror.List
// roundTripper is a http.RoundTripper that adds the Authorization header.
roundTripper struct {
token string
extraHeaders map[string]string
base http.RoundTripper
}
)
func (e errlist) Error() string {
s := strings.TrimPrefix(gqlerror.List(e).Error(), "input:")
return strings.TrimSpace(s)
}
// RoundTrip implements http.RoundTripper.
func (r *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
SetHeader(req, r.token)
for k, v := range r.extraHeaders {
req.Header.Set(k, v)
}
return r.base.RoundTrip(req)
}
// HTTPError represents a generic HTTP error. Hence, non 2xx status codes.
type HTTPError struct {
StatusCode int
Message string
}
func (e *HTTPError) Error() string {
return fmt.Sprintf("unexpected error code %d: %s", e.StatusCode, e.Message)
}
// RedactedURL returns a URL string with the userinfo redacted.
func RedactedURL(s string) (string, error) {
u, err := sqlclient.ParseURL(s)
if err != nil {
return "", err
}
return u.Redacted(), nil
}
// version of the CLI set by cmdapi.
var version = "development"
// SetVersion allow cmdapi to set the version
// of the CLI provided at build time.
func SetVersion(v, flavor string) {
version = v
if flavor != "" {
version += "-" + flavor
}
}
// SetHeader sets header fields for cloud requests.
func SetHeader(req *http.Request, token string) {
for k, v := range header(token) {
req.Header.Set(k, v[0])
}
}
func header(token string) http.Header {
h := make(http.Header)
h.Set("Authorization", "Bearer "+token)
h.Set("User-Agent", UserAgent())
h.Set("Content-Type", "application/json")
return h
}
// UserAgent is the value the CLI uses in the User-Agent HTTP header.
func UserAgent(systems ...string) string {
sysInfo := runtime.GOOS + "/" + runtime.GOARCH
if len(systems) > 0 {
systems = slices.DeleteFunc(systems, func(s string) bool {
return strings.TrimSpace(s) == ""
})
sysInfo = strings.Join(slices.Insert(systems, 0, sysInfo), "; ")
}
return fmt.Sprintf("Atlas/%s (%s)", version, sysInfo)
}
================================================
FILE: cmd/atlas/internal/cloudapi/client_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package cloudapi
import (
"net/url"
)
func testingURL(endpoint string) bool {
u, err := url.Parse(endpoint)
if err != nil {
return false
}
host := u.Hostname()
return host == "localhost" || host == "127.0.0.1"
}
================================================
FILE: cmd/atlas/internal/cloudapi/client_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cloudapi
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"runtime"
"strings"
"testing"
"ariga.io/atlas/sql/migrate"
"github.com/stretchr/testify/require"
)
func TestClient_Dir(t *testing.T) {
var dir migrate.MemDir
require.NoError(t, dir.WriteFile("1.sql", []byte("create table foo (id int)")))
ad, err := migrate.ArchiveDir(&dir)
require.NoError(t, err)
SetVersion("v0.13.0", "")
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var input struct {
Variables struct {
DirInput DirInput `json:"input"`
} `json:"variables"`
}
err := json.NewDecoder(r.Body).Decode(&input)
require.NoError(t, err)
require.Equal(t, "foo", input.Variables.DirInput.Name)
require.Equal(t, "x", input.Variables.DirInput.Tag)
require.Equal(t, "Bearer atlas", r.Header.Get("Authorization"))
expUA := fmt.Sprintf("Atlas/v0.13.0 (%s/%s)", runtime.GOOS, runtime.GOARCH)
require.Equal(t, expUA, r.Header.Get("User-Agent"))
fmt.Fprintf(w, `{"data":{"dirState":{"content":%q}}}`, base64.StdEncoding.EncodeToString(ad))
}))
client := New(srv.URL, "atlas")
defer srv.Close()
gd, err := client.Dir(context.Background(), DirInput{
Name: "foo",
Tag: "x",
})
require.NoError(t, err)
gcheck, err := gd.Checksum()
require.NoError(t, err)
dcheck, err := dir.Checksum()
require.NoError(t, err)
require.Equal(t, dcheck.Sum(), gcheck.Sum())
}
func TestClient_GraphQLError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnprocessableEntity)
_, err := w.Write([]byte(`{"errors":[{"message":"error\n","path":["variable","input","driver"],"extensions":{}}],"data":null}`))
require.NoError(t, err)
}))
client := New(srv.URL, "atlas")
defer srv.Close()
link, err := client.ReportMigration(context.Background(), ReportMigrationInput{
EnvName: "foo",
ProjectName: "bar",
})
require.EqualError(t, err, "variable.input.driver error", "error is trimmed")
require.Empty(t, link)
}
func TestClient_HTTPError(t *testing.T) {
var (
body string
code = http.StatusInternalServerError
)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, body, code)
}))
client := New(srv.URL, "atlas")
defer srv.Close()
body = "internal error"
_, err := client.ReportMigration(context.Background(), ReportMigrationInput{
EnvName: "foo",
ProjectName: "bar",
})
require.EqualError(t, err, `unexpected error code 500: internal error`)
// Error should be limited to 1MB.
body = fmt.Sprintf("%s!", strings.Repeat("a", 1<<20))
_, err = client.ReportMigration(context.Background(), ReportMigrationInput{
EnvName: "foo",
ProjectName: "bar",
})
require.ErrorContains(t, err, "unexpected error code 500: a")
require.NotContains(t, err.Error(), "!")
// Unauthorized error.
body = "unauthorized"
code = http.StatusUnauthorized
_, err = client.ReportMigration(context.Background(), ReportMigrationInput{
EnvName: "foo",
ProjectName: "bar",
})
require.ErrorIs(t, err, ErrUnauthorized)
code = http.StatusForbidden
body = "Forbidden"
_, err = client.ReportMigration(context.Background(), ReportMigrationInput{
EnvName: "foo",
ProjectName: "bar",
})
require.EqualError(t, err, "unexpected error code 403: Forbidden")
code = http.StatusConflict
body = `{"errors":[{"message":"conflict\n","path":["variable","input","driver"],"extensions":{}}],"data":null}`
_, err = client.ReportMigration(context.Background(), ReportMigrationInput{
EnvName: "foo",
ProjectName: "bar",
})
require.EqualError(t, err, "variable.input.driver conflict", "GraphQL error")
}
func TestClient_ReportMigration(t *testing.T) {
const project, env = "atlas", "dev"
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var input struct {
Variables struct {
Input ReportMigrationInput `json:"input"`
} `json:"variables"`
}
err := json.NewDecoder(r.Body).Decode(&input)
require.NoError(t, err)
require.Equal(t, env, input.Variables.Input.EnvName)
require.Equal(t, project, input.Variables.Input.ProjectName)
fmt.Fprintf(w, `{"data":{"reportMigration":{"url":"https://atlas.com"}}}`)
}))
client := New(srv.URL, "atlas")
defer srv.Close()
link, err := client.ReportMigration(context.Background(), ReportMigrationInput{
EnvName: env,
ProjectName: project,
})
require.NoError(t, err)
require.NotEmpty(t, link)
}
func TestClient_ReportMigrationSet(t *testing.T) {
const (
planned = 2
id, log, project, env = "deployment-set-1", "started deployment", "atlas", "dev"
)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var input struct {
Variables struct {
Input ReportMigrationSetInput `json:"input"`
} `json:"variables"`
}
err := json.NewDecoder(r.Body).Decode(&input)
require.NoError(t, err)
require.Equal(t, id, input.Variables.Input.ID)
require.Equal(t, []ReportStep{{Text: log}}, input.Variables.Input.Log)
require.Equal(t, planned, input.Variables.Input.Planned)
require.Equal(t, env, input.Variables.Input.Completed[0].EnvName)
require.Equal(t, project, input.Variables.Input.Completed[0].ProjectName)
require.Equal(t, "dir-1", input.Variables.Input.Completed[0].DirName)
require.Equal(t, env, input.Variables.Input.Completed[1].EnvName)
require.Equal(t, project, input.Variables.Input.Completed[1].ProjectName)
require.Equal(t, "dir-2", input.Variables.Input.Completed[1].DirName)
fmt.Fprintf(w, `{"data":{"reportMigrationSet":{"url":"https://atlas.com"}}}`)
}))
client := New(srv.URL, "atlas")
defer srv.Close()
link, err := client.ReportMigrationSet(context.Background(), ReportMigrationSetInput{
ID: id,
Planned: planned,
Log: []ReportStep{{Text: log}},
Completed: []ReportMigrationInput{
{
EnvName: env,
ProjectName: project,
DirName: "dir-1",
},
{
EnvName: env,
ProjectName: project,
DirName: "dir-2",
},
},
})
require.NoError(t, err)
require.NotEmpty(t, link)
}
func TestRedactedURL(t *testing.T) {
u, err := RedactedURL("mysql://user:pass@:3306/db")
require.NoError(t, err)
require.Equal(t, "mysql://user:xxxxx@:3306/db", u)
u, err = RedactedURL("\\n mysql://user:pass@:3306/db")
require.EqualError(t, err, `first path segment in URL cannot contain colon`)
require.Empty(t, u)
}
func TestUserAgent(t *testing.T) {
platform := runtime.GOOS + "/" + runtime.GOARCH
require.Equal(t, fmt.Sprintf("Atlas/%s (%s)", version, platform), UserAgent())
require.Equal(t, fmt.Sprintf("Atlas/%s (%s; foo/bar; bar/baz)", version, platform), UserAgent("foo/bar", "bar/baz"))
require.Equal(t, fmt.Sprintf("Atlas/%s (%s; bar/baz)", version, platform), UserAgent(" ", "", "bar/baz"))
}
func TestClient_AddHeader(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "val", r.Header.Get("key"))
}))
client := New(srv.URL, "atlas")
defer srv.Close()
client.AddHeader("key", "val")
_, err := client.ReportMigration(context.Background(), ReportMigrationInput{
EnvName: "foo",
ProjectName: "bar",
})
require.NoError(t, err)
}
func TestClient_Retry(t *testing.T) {
var (
calls = []int{http.StatusInternalServerError, http.StatusInternalServerError, http.StatusOK}
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "val", r.Header.Get("key"))
require.Equal(t, "Bearer atlas", r.Header.Get("Authorization"))
w.WriteHeader(calls[0])
calls = calls[1:]
}))
client = New(srv.URL, "atlas")
)
defer srv.Close()
client.AddHeader("key", "val")
_, err := client.ReportMigration(context.Background(), ReportMigrationInput{
EnvName: "foo",
})
require.NoError(t, err)
require.Empty(t, calls)
}
================================================
FILE: cmd/atlas/internal/cmdapi/cmdapi.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Package cmdapi holds the atlas commands used to build an atlas distribution.
package cmdapi
import (
"context"
"encoding/csv"
"errors"
"fmt"
"net/url"
"sort"
"strings"
"time"
"ariga.io/atlas/cmd/atlas/internal/cmdext"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/zclconf/go-cty/cty"
"golang.org/x/exp/maps"
"golang.org/x/mod/semver"
)
var (
// Root represents the root command when called without any subcommands.
Root = &cobra.Command{
Use: "atlas",
Short: "Manage your database schema as code",
SilenceUsage: true,
}
// GlobalFlags contains flags common to many Atlas sub-commands.
GlobalFlags struct {
// Config defines the path to the Atlas project/config file.
ConfigURL string
// SelectedEnv contains the environment selected from the active project via the --env flag.
SelectedEnv string
// Vars contains the input variables passed from the CLI to Atlas DDL or project files.
Vars Vars
}
// flavor holds Atlas flavor. Custom flavors (like the community build) should set this by build flag
// "-X 'ariga.io/atlas/cmd/atlas/internal/cmdapi.flavor=community'"
flavor string
// version holds Atlas version. When built with cloud packages should be set by build flag, e.g.
// "-X 'ariga.io/atlas/cmd/atlas/internal/cmdapi.version=v0.1.2'"
version string
// versionCmd represents the subcommand 'atlas version'.
versionCmd = &cobra.Command{
Use: "version",
Short: "Prints this Atlas CLI version information.",
Run: func(cmd *cobra.Command, _ []string) {
var (
f = versionFmt
args []any
)
if flavor != "" {
f += "%s "
args = append(args, flavor)
}
f += "version %s\n%s\n%s"
v, u := parseV(version)
args = append(args, v, u, versionInfo)
cmd.Printf(f, args...)
},
}
// license holds Atlas license. When built with cloud packages should be set by build flag
// "-X 'ariga.io/atlas/cmd/atlas/internal/cmdapi.license=${license}'"
license = `LICENSE
Atlas is licensed under Apache 2.0 as found in https://github.com/ariga/atlas/blob/master/LICENSE.`
// licenseCmd represents the subcommand 'atlas license'.
licenseCmd = &cobra.Command{
Use: "license",
Short: "Display license information",
Run: func(cmd *cobra.Command, _ []string) {
cmd.Println(license)
},
}
)
type (
// ErrorFormatter implemented by the errors below to
// allow them format command output on error.
ErrorFormatter interface {
FormatError(*cobra.Command)
}
// FormattedError is an error that format the command output when returned.
FormattedError struct {
Err error
Prefix string // Prefix to use on error.
Silent bool // Silent errors are not printed.
}
// AbortError returns a command error that is formatted as "Abort: ..." when
// the execution is aborted by the user.
AbortError struct {
Err error
}
// Aborter allows errors to signal if the error is an abort error.
Aborter interface {
error
IsAbort()
}
)
func (e *FormattedError) Error() string { return e.Err.Error() }
func (e *FormattedError) FormatError(cmd *cobra.Command) {
cmd.SilenceErrors = e.Silent
if e.Prefix != "" {
cmd.SetErrPrefix(e.Prefix)
}
}
// AbortErrorf is like fmt.Errorf for creating AbortError.
func AbortErrorf(format string, a ...any) error {
return &AbortError{Err: fmt.Errorf(format, a...)}
}
func (e *AbortError) Error() string { return e.Err.Error() }
func (e *AbortError) FormatError(cmd *cobra.Command) {
cmd.SetErrPrefix("Abort:")
}
func (e *AbortError) Unwrap() error {
return e.Err
}
// RunE wraps the command cobra.Command.RunE function with additional postrun logic.
func RunE(f func(*cobra.Command, []string) error) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) (err error) {
if err = f(cmd, args); err != nil {
if err1 := (Aborter)(nil); errors.As(err, &err1) {
err = &AbortError{Err: err}
}
if ef, ok := err.(ErrorFormatter); ok {
ef.FormatError(cmd)
}
}
return err
}
}
func init() {
Root.AddCommand(versionCmd)
Root.AddCommand(licenseCmd)
// Register a global function to clean up the global
// flags regardless if the command passed or failed.
cobra.OnFinalize(func() {
GlobalFlags.ConfigURL = ""
GlobalFlags.Vars = nil
GlobalFlags.SelectedEnv = ""
})
}
// parseV returns a user facing version and release notes url
func parseV(version string) (string, string) {
u := "https://github.com/ariga/atlas/releases/latest"
if ok := semver.IsValid(version); !ok {
return "- development", u
}
s := strings.Split(version, "-")
if len(s) != 0 && s[len(s)-1] != "canary" {
u = fmt.Sprintf("https://github.com/ariga/atlas/releases/tag/%s", version)
}
return version, u
}
// Version returns the current Atlas binary version.
func Version() string {
return version
}
// Vars implements pflag.Value.
type Vars map[string]cty.Value
// String implements pflag.Value.String.
func (v Vars) String() string {
var (
b strings.Builder
ks = maps.Keys(v)
)
sort.Strings(ks)
for _, k := range ks {
if b.Len() > 0 {
b.WriteString(", ")
}
b.WriteString(k)
b.WriteString(":")
switch v1 := v[k]; v1.Type() {
case cty.String:
b.WriteString(v1.AsString())
case cty.List(cty.String):
b.WriteString("[")
for i, v2 := range v1.AsValueSlice() {
if i > 0 {
b.WriteString(", ")
}
b.WriteString(v2.AsString())
}
b.WriteString("]")
default:
b.WriteString(v1.GoString())
}
}
return "[" + b.String() + "]"
}
// Copy returns a copy of the current variables.
func (v Vars) Copy() Vars {
vc := make(Vars)
for k := range v {
vc[k] = v[k]
}
return vc
}
// Replace overrides the variables.
func (v *Vars) Replace(vc Vars) {
*v = vc
}
// Set implements pflag.Value.Set.
func (v *Vars) Set(s string) error {
if *v == nil {
*v = make(Vars)
}
kvs, err := csv.NewReader(strings.NewReader(s)).Read()
if err != nil {
return err
}
for i := range kvs {
kv := strings.SplitN(kvs[i], "=", 2)
if len(kv) != 2 {
return fmt.Errorf("variables must be format as key=value, got: %q", kvs[i])
}
v1 := cty.StringVal(kv[1])
switch v0, ok := (*v)[kv[0]]; {
case ok && v0.Type().IsListType():
(*v)[kv[0]] = cty.ListVal(append(v0.AsValueSlice(), v1))
case ok:
(*v)[kv[0]] = cty.ListVal([]cty.Value{v0, v1})
default:
(*v)[kv[0]] = v1
}
}
return nil
}
// Type implements pflag.Value.Type.
func (v *Vars) Type() string {
return "="
}
const (
flagAllowDirty = "allow-dirty"
flagEdit = "edit"
flagAutoApprove = "auto-approve"
flagBaseline = "baseline"
flagConfig = "config"
flagContext = "context"
flagDevURL = "dev-url"
flagDirURL = "dir"
flagDirFormat = "dir-format"
flagDryRun = "dry-run"
flagEnv = "env"
flagExclude = "exclude"
flagInclude = "include"
flagFile = "file"
flagFrom = "from"
flagFromShort = "f"
flagFormat = "format"
flagGitBase = "git-base"
flagGitDir = "git-dir"
flagLatest = "latest"
flagLockTimeout = "lock-timeout"
flagLog = "log"
flagPlan = "plan"
flagRevisionSchema = "revisions-schema"
flagSchema = "schema"
flagSchemaShort = "s"
flagTo = "to"
flagTxMode = "tx-mode"
flagExecOrder = "exec-order"
flagURL = "url"
flagURLShort = "u"
flagVar = "var"
flagQualifier = "qualifier"
)
func addGlobalFlags(set *pflag.FlagSet) {
set.StringVar(&GlobalFlags.SelectedEnv, flagEnv, "", "set which env from the config file to use")
set.Var(&GlobalFlags.Vars, flagVar, "input variables")
set.StringVarP(&GlobalFlags.ConfigURL, flagConfig, "c", defaultConfigPath, "select config (project) file using URL format")
}
func addFlagAutoApprove(set *pflag.FlagSet, target *bool) {
set.BoolVar(target, flagAutoApprove, false, "apply changes without prompting for approval")
}
func addFlagDirFormat(set *pflag.FlagSet, target *string) {
set.StringVar(target, flagDirFormat, "atlas", "select migration file format")
}
func addFlagLockTimeout(set *pflag.FlagSet, target *time.Duration) {
set.DurationVar(target, flagLockTimeout, 10*time.Second, "set how long to wait for the database lock")
}
// addFlagURL adds a URL flag. If given, args[0] override the name, args[1] the shorthand, args[2] the default value.
func addFlagDirURL(set *pflag.FlagSet, target *string, args ...string) {
name, short, val := flagDirURL, "", "file://migrations"
switch len(args) {
case 3:
val = args[2]
fallthrough
case 2:
short = args[1]
fallthrough
case 1:
name = args[0]
}
set.StringVarP(target, name, short, val, "select migration directory using URL format")
}
func addFlagDevURL(set *pflag.FlagSet, target *string) {
set.StringVar(
target,
flagDevURL,
"",
"[driver://username:password@address/dbname?param=value] select a dev database using the URL format",
)
}
func addFlagDryRun(set *pflag.FlagSet, target *bool) {
set.BoolVar(target, flagDryRun, false, "print SQL without executing it")
}
func addFlagExclude(set *pflag.FlagSet, target *[]string) {
set.StringSliceVar(
target,
flagExclude,
nil,
"list of glob patterns used to filter resources from applying",
)
}
func addFlagInclude(set *pflag.FlagSet, target *[]string) {
set.StringSliceVar(
target,
flagInclude,
nil,
"list of glob patterns used to select which resources to keep in inspection",
)
}
func addFlagLog(set *pflag.FlagSet, target *string) {
set.StringVar(target, flagLog, "", "Go template to use to format the output")
// Use MarkHidden instead of MarkDeprecated to avoid
// spam users' system logs with deprecation warnings.
cobra.CheckErr(set.MarkHidden(flagLog))
}
func addFlagFormat(set *pflag.FlagSet, target *string) {
set.StringVar(target, flagFormat, "", "Go template to use to format the output")
}
func addFlagRevisionSchema(set *pflag.FlagSet, target *string) {
set.StringVar(target, flagRevisionSchema, "", "name of the schema the revisions table resides in")
}
func addFlagSchemas(set *pflag.FlagSet, target *[]string) {
set.StringSliceVarP(
target,
flagSchema, flagSchemaShort,
nil,
"set schema names",
)
}
// addFlagURL adds a URL flag. If given, args[0] override the name, args[1] the shorthand.
func addFlagURL(set *pflag.FlagSet, target *string, args ...string) {
name, short := flagURL, flagURLShort
switch len(args) {
case 2:
short = args[1]
fallthrough
case 1:
name = args[0]
}
set.StringVarP(
target,
name, short,
"",
"[driver://username:password@address/dbname?param=value] select a resource using the URL format",
)
}
func addFlagURLs(set *pflag.FlagSet, target *[]string, args ...string) {
name, short := flagURL, flagURLShort
switch len(args) {
case 2:
short = args[1]
fallthrough
case 1:
name = args[0]
}
set.StringSliceVarP(
target,
name, short,
nil,
"[driver://username:password@address/dbname?param=value] select a resource using the URL format",
)
}
func addFlagToURLs(set *pflag.FlagSet, target *[]string) {
set.StringSliceVarP(target, flagTo, "", nil, "[driver://username:password@address/dbname?param=value] select a desired state using the URL format")
}
// maySetFlag sets the flag with the provided name to envVal if such a flag exists
// on the cmd, it was not set by the user via the command line and if envVal is not
// an empty string.
func maySetFlag(cmd *cobra.Command, name, envVal string) error {
if f := cmd.Flag(name); f == nil || f.Changed || envVal == "" {
return nil
}
return cmd.Flags().Set(name, envVal)
}
// resetFromEnv traverses the command flags, records what flags
// were not set by the user and returns a callback to clear them
// after it was set by the current environment.
func resetFromEnv(cmd *cobra.Command) func() {
mayReset := make(map[string]func() error)
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if f.Changed {
return
}
vs := f.Value.String()
r := func() error { return f.Value.Set(vs) }
if v, ok := f.Value.(*Vars); ok {
vs := v.Copy()
r = func() error {
v.Replace(vs.Copy())
return nil
}
} else if v, ok := f.Value.(pflag.SliceValue); ok {
vs := v.GetSlice()
r = func() error {
return v.Replace(vs)
}
}
mayReset[f.Name] = r
})
return func() {
for name, reset := range mayReset {
if f := cmd.Flag(name); f != nil && f.Changed {
f.Changed = false
// Unexpected error, because this flag was set before.
cobra.CheckErr(reset())
}
}
}
}
// stateReaderConfig is given to stateReader.
type stateReaderConfig struct {
urls []string // urls to create a migrate.StateReader from
client, dev *sqlclient.Client // database connections, while dev is considered a dev database, client is not
schemas []string // schemas to work on
exclude []string // exclude flag values
include []string // include flag values
withPos bool // indicate if schema.Pos should be loaded.
vars Vars
}
// Exported is a temporary method to convert the stateReaderConfig to cmdext.StateReaderConfig.
func (c *stateReaderConfig) Exported() (*cmdext.StateReaderConfig, error) {
var (
err error
parsed = make([]*url.URL, len(c.urls))
)
for i, u := range c.urls {
if parsed[i], err = sqlclient.ParseURL(u); err != nil {
return nil, err
}
}
return &cmdext.StateReaderConfig{
URLs: parsed,
Client: c.client,
Dev: c.dev,
Schemas: c.schemas,
Exclude: c.exclude,
Include: c.include,
WithPos: c.withPos,
Vars: c.vars,
}, nil
}
// readerUseDev reports if any of the URL uses the dev-database.
func readerUseDev(env *Env, urls ...string) (bool, error) {
s, err := selectScheme(urls)
if err != nil {
return false, err
}
switch {
case s == envAttrScheme && env != nil && len(urls) == 1:
u, err := env.VarFromURL(urls[0])
if err != nil {
return false, err
}
// No circular reference possible with env:// variable.
return readerUseDev(env, u)
case s == cmdext.SchemaTypeFile, s == cmdext.SchemaTypeAtlas:
return true, nil
default:
return cmdext.States.HasLoader(s), nil
}
}
// stateReader returns a migrate.StateReader that reads the state from the given urls.
func stateReader(ctx context.Context, env *Env, config *stateReaderConfig) (*cmdext.StateReadCloser, error) {
excfg, err := config.Exported()
if err != nil {
return nil, err
}
scheme, err := selectScheme(config.urls)
if err != nil {
return nil, err
}
switch scheme {
// "file" scheme is valid for both migration directory and HCL paths.
case cmdext.SchemaTypeFile:
switch ext, err := cmdext.FilesExt(excfg.URLs); {
case err != nil:
return nil, err
case ext == cmdext.FileTypeHCL:
return cmdext.StateReaderHCL(ctx, excfg)
case ext == cmdext.FileTypeSQL:
return cmdext.StateReaderSQL(ctx, excfg)
default:
panic("unreachable") // checked by filesExt.
}
// "atlas" scheme represents an Atlas Cloud schema.
case cmdext.SchemaTypeAtlas:
return cmdext.StateReaderAtlas(ctx, excfg)
// "env" scheme represents an attribute defined
// on the selected environment.
case envAttrScheme:
switch {
case GlobalFlags.SelectedEnv == "":
return nil, errors.New("cannot use env:// variables without selecting an environment")
case len(config.urls) != 1:
return nil, errors.New("cannot use multiple env:// variables in a single flag")
default:
u, err := env.VarFromURL(config.urls[0])
if err != nil {
return nil, err
}
cfg := *config
cfg.urls = []string{u}
return stateReader(ctx, env, &cfg)
}
default:
// In case there is an external state-loader registered with this scheme.
if l, ok := cmdext.States.Loader(scheme); ok {
rc, err := l.LoadState(ctx, excfg)
if err != nil {
return nil, err
}
return rc, nil
}
// All other schemes are database (or docker) connections.
c, err := env.openClient(ctx, config.urls[0]) // call to selectScheme already checks for len > 0
if err != nil {
return nil, err
}
var sr migrate.StateReader
switch c.URL.Schema {
case "":
sr = migrate.RealmConn(c.Driver, &schema.InspectRealmOption{
Schemas: config.schemas,
Exclude: config.exclude,
Include: config.include,
})
default:
sr = migrate.SchemaConn(c.Driver, c.URL.Schema, &schema.InspectOptions{
Exclude: config.exclude,
Include: config.include,
})
}
return &cmdext.StateReadCloser{
StateReader: sr,
Closer: c,
Schema: c.URL.Schema,
}, nil
}
}
const localStateFile = "local-community.json"
// LocalState keeps track of local state to enhance developer experience.
type LocalState struct {
UpgradeSuggested time.Time `json:"v1.us"`
}
================================================
FILE: cmd/atlas/internal/cmdapi/cmdapi_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package cmdapi
import (
"context"
"errors"
"fmt"
"net/url"
"os"
"testing"
"text/template"
"time"
"ariga.io/atlas/cmd/atlas/internal/cmdext"
"ariga.io/atlas/cmd/atlas/internal/cmdlog"
"ariga.io/atlas/cmd/atlas/internal/cmdstate"
cmdmigrate "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/cmd/atlas/internal/migratelint"
"ariga.io/atlas/schemahcl"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlcheck"
"ariga.io/atlas/sql/sqlclient"
"github.com/spf13/cobra"
)
func init() {
schemaCmd := schemaCmd()
schemaCmd.AddCommand(
schemaApplyCmd(),
schemaCleanCmd(),
schemaDiffCmd(),
schemaFmtCmd(),
schemaInspectCmd(),
unsupportedCommand("schema", "test"),
unsupportedCommand("schema", "plan"),
unsupportedCommand("schema", "push"),
)
Root.AddCommand(schemaCmd)
migrateCmd := migrateCmd()
migrateCmd.AddCommand(
migrateApplyCmd(),
migrateDiffCmd(),
migrateHashCmd(),
migrateImportCmd(),
migrateLintCmd(),
migrateNewCmd(),
migrateSetCmd(),
migrateStatusCmd(),
migrateValidateCmd(),
unsupportedCommand("migrate", "checkpoint"),
unsupportedCommand("migrate", "down"),
unsupportedCommand("migrate", "rebase"),
unsupportedCommand("migrate", "rm"),
unsupportedCommand("migrate", "edit"),
unsupportedCommand("migrate", "push"),
unsupportedCommand("migrate", "test"),
)
Root.AddCommand(migrateCmd)
}
// unsupportedCommand create a stub command that reports
// the command is not supported by this build.
func unsupportedCommand(cmd, sub string) *cobra.Command {
s := unsupportedMessage(cmd, sub)
c := &cobra.Command{
Hidden: true,
Use: fmt.Sprintf("%s is not supported by this build", sub),
Short: s,
Long: s,
RunE: RunE(func(*cobra.Command, []string) error {
return AbortErrorf("%s", s)
}),
}
c.SetHelpTemplate(s + "\n")
return c
}
// unsupportedMessage returns a message informing the user that the command
// or one of its options are not supported. For example:
//
// unsupportedMessage("migrate", "checkpoint")
// unsupportedMessage("schema", "apply --plan")
func unsupportedMessage(cmd, sub string) string {
return fmt.Sprintf(
`'atlas %s %s' is not supported by the community version.
To install the non-community version of Atlas, use the following command:
curl -sSf https://atlasgo.sh | sh
Or, visit the website to see all installation options:
https://atlasgo.io/docs#installation
`,
cmd, sub,
)
}
type (
// Project represents an atlas.hcl project config file.
Project struct {
Envs []*Env `spec:"env"` // List of environments
Lint *Lint `spec:"lint"` // Optional global lint policy
Diff *Diff `spec:"diff"` // Optional global diff policy
Test *Test `spec:"test"` // Optional test configuration
cloud *cmdext.AtlasConfig
}
)
const (
envSkipUpgradeSuggestions = "ATLAS_NO_UPGRADE_SUGGESTIONS"
oneWeek = 7 * 24 * time.Hour
)
// maySuggestUpgrade informs the user about the limitations of the community edition to stderr
// at most once a week. The user can disable this message by setting the ATLAS_NO_UPGRADE_SUGGESTIONS
// environment variable.
func maySuggestUpgrade(cmd *cobra.Command) {
if os.Getenv(envSkipUpgradeSuggestions) != "" || testing.Testing() {
return
}
state := cmdstate.File[LocalState]{Name: localStateFile}
prev, err := state.Read()
if err != nil {
return
}
if time.Since(prev.UpgradeSuggested) < oneWeek {
return
}
s := `Notice: This Atlas edition lacks support for features such as checkpoints,
testing, down migrations, and more. Additionally, advanced database objects such as views,
triggers, and stored procedures are not supported. To read more: https://atlasgo.io/community-edition
To install the non-community version of Atlas, use the following command:
curl -sSf https://atlasgo.sh | sh
Or, visit the website to see all installation options:
https://atlasgo.io/docs#installation
`
_ = cmdlog.WarnOnce(cmd.ErrOrStderr(), cmdlog.ColorCyan(s))
prev.UpgradeSuggested = time.Now()
_ = state.Write(prev)
}
// migrateLintSetFlags allows setting extra flags for the 'migrate lint' command.
func migrateLintSetFlags(*cobra.Command, *migrateLintFlags) {}
// migrateLintRun is the run command for 'migrate lint'.
func migrateLintRun(cmd *cobra.Command, _ []string, flags migrateLintFlags, env *Env) error {
dev, err := sqlclient.Open(cmd.Context(), flags.devURL)
if err != nil {
return err
}
defer dev.Close()
dir, err := cmdmigrate.Dir(cmd.Context(), flags.dirURL, false)
if err != nil {
return err
}
var detect migratelint.ChangeDetector
switch {
case flags.latest == 0 && flags.gitBase == "":
return fmt.Errorf("--%s or --%s is required", flagLatest, flagGitBase)
case flags.latest > 0 && flags.gitBase != "":
return fmt.Errorf("--%s and --%s are mutually exclusive", flagLatest, flagGitBase)
case flags.latest > 0:
detect = migratelint.LatestChanges(dir, int(flags.latest))
case flags.gitBase != "":
detect, err = migratelint.NewGitChangeDetector(
dir,
migratelint.WithWorkDir(flags.gitDir),
migratelint.WithBase(flags.gitBase),
migratelint.WithMigrationsPath(dir.(interface{ Path() string }).Path()),
)
if err != nil {
return err
}
}
format := migratelint.DefaultTemplate
if f := flags.logFormat; f != "" {
format, err = template.New("format").Funcs(migratelint.TemplateFuncs).Parse(f)
if err != nil {
return fmt.Errorf("parse format: %w", err)
}
}
az, err := sqlcheck.AnalyzerFor(dev.Name, env.Lint.Remain())
if err != nil {
return err
}
r := &migratelint.Runner{
Dev: dev,
Dir: dir,
ChangeDetector: detect,
ReportWriter: &migratelint.TemplateWriter{
T: format,
W: cmd.OutOrStdout(),
},
Analyzers: az,
}
err = r.Run(cmd.Context())
// Print the error in case it was not printed before.
cmd.SilenceErrors = errors.As(err, &migratelint.SilentError{})
cmd.SilenceUsage = cmd.SilenceErrors
return err
}
func migrateDiffRun(cmd *cobra.Command, args []string, flags migrateDiffFlags, env *Env) error {
if flags.dryRun {
return errors.New("'--dry-run' is not supported in the community version")
}
ctx := cmd.Context()
dev, err := sqlclient.Open(ctx, flags.devURL)
if err != nil {
return err
}
defer dev.Close()
// Acquire a lock.
unlock, err := dev.Lock(ctx, "atlas_migrate_diff", flags.lockTimeout)
if err != nil {
return fmt.Errorf("acquiring database lock: %w", err)
}
// If unlocking fails notify the user about it.
defer func() { cobra.CheckErr(unlock()) }()
// Open the migration directory.
u, err := url.Parse(flags.dirURL)
if err != nil {
return err
}
dir, err := cmdmigrate.DirURL(ctx, u, false)
if err != nil {
return err
}
if flags.edit {
l, ok := dir.(*migrate.LocalDir)
if !ok {
return fmt.Errorf("--edit flag supports only atlas directories, but got: %T", dir)
}
dir = &editDir{l}
}
var name, indent string
if len(args) > 0 {
name = args[0]
}
f, err := cmdmigrate.Formatter(u)
if err != nil {
return err
}
if f, indent, err = mayIndent(u, f, flags.format); err != nil {
return err
}
diffOpts := diffOptions(cmd, env)
// If there is a state-loader that requires a custom
// 'migrate diff' handling, offload it the work.
if d, ok := cmdext.States.Differ(flags.desiredURLs); ok {
err := d.MigrateDiff(ctx, &cmdext.MigrateDiffOptions{
To: flags.desiredURLs,
Name: name,
Indent: indent,
Dir: dir,
Dev: dev,
Options: diffOpts,
})
return maskNoPlan(cmd, err)
}
// Get a state reader for the desired state.
desired, err := stateReader(ctx, env, &stateReaderConfig{
urls: flags.desiredURLs,
dev: dev,
client: dev,
schemas: flags.schemas,
vars: env.Vars(),
})
if err != nil {
return err
}
defer desired.Close()
opts := []migrate.PlannerOption{
migrate.PlanFormat(f),
migrate.PlanWithIndent(indent),
migrate.PlanWithDiffOptions(diffOpts...),
}
if dev.URL.Schema != "" {
// Disable tables qualifier in schema-mode.
opts = append(opts, migrate.PlanWithSchemaQualifier(flags.qualifier))
}
// Plan the changes and create a new migration file.
pl := migrate.NewPlanner(dev.Driver, dir, opts...)
plan, err := func() (*migrate.Plan, error) {
if dev.URL.Schema != "" {
return pl.PlanSchema(ctx, name, desired.StateReader)
}
return pl.Plan(ctx, name, desired.StateReader)
}()
var cerr *migrate.NotCleanError
switch {
case errors.As(err, &cerr) && dev.URL.Schema == "" && desired.Schema != "":
return fmt.Errorf("dev database is not clean (%s). Add a schema to the URL to limit the scope of the connection", cerr.Reason)
case err != nil:
return maskNoPlan(cmd, err)
default:
return pl.WritePlan(plan)
}
}
// schemaApplyRunE is the community version of the 'atlas schema apply' command.
func schemaApplyRunE(cmd *cobra.Command, _ []string, flags *schemaApplyFlags) error {
switch {
case flags.edit:
return AbortErrorf("%s", unsupportedMessage("schema", "apply --edit"))
case flags.planURL != "":
return AbortErrorf("%s", unsupportedMessage("schema", "apply --plan"))
case len(flags.include) > 0:
return AbortErrorf("%s", unsupportedMessage("schema", "apply --include"))
case GlobalFlags.SelectedEnv == "":
env, err := selectEnv(cmd)
if err != nil {
return err
}
return schemaApplyRun(cmd, *flags, env)
default:
_, envs, err := EnvByName(cmd, GlobalFlags.SelectedEnv, GlobalFlags.Vars)
if err != nil {
return err
}
if len(envs) != 1 {
return fmt.Errorf("multi-environment %q is not supported", GlobalFlags.SelectedEnv)
}
if err := setSchemaEnvFlags(cmd, envs[0]); err != nil {
return err
}
return schemaApplyRun(cmd, *flags, envs[0])
}
}
func schemaApplyRun(cmd *cobra.Command, flags schemaApplyFlags, env *Env) error {
var (
err error
ctx = cmd.Context()
dev *sqlclient.Client
format = cmdlog.SchemaPlanTemplate
)
if err = flags.check(env); err != nil {
return err
}
if v := flags.logFormat; v != "" {
if !flags.dryRun && !flags.autoApprove {
return errors.New(`--log and --format can only be used with --dry-run or --auto-approve`)
}
if format, err = template.New("format").Funcs(cmdlog.ApplyTemplateFuncs).Parse(v); err != nil {
return fmt.Errorf("parse log format: %w", err)
}
}
if flags.devURL != "" {
if dev, err = sqlclient.Open(ctx, flags.devURL); err != nil {
return err
}
defer dev.Close()
}
from, err := stateReader(ctx, env, &stateReaderConfig{
urls: []string{flags.url},
schemas: flags.schemas,
exclude: flags.exclude,
})
if err != nil {
return err
}
defer from.Close()
client, ok := from.Closer.(*sqlclient.Client)
if !ok {
return errors.New("--url must be a database connection")
}
to, err := stateReader(ctx, env, &stateReaderConfig{
urls: flags.toURLs,
dev: dev,
client: client,
schemas: flags.schemas,
exclude: flags.exclude,
vars: env.Vars(),
})
if err != nil {
return err
}
defer to.Close()
diff, err := computeDiff(ctx, client, from, to, diffOptions(cmd, env)...)
if err != nil {
return err
}
maySuggestUpgrade(cmd)
// Returning at this stage should
// not trigger the help message.
cmd.SilenceUsage = true
switch changes := diff.changes; {
case len(changes) == 0:
return format.Execute(cmd.OutOrStdout(), &cmdlog.SchemaApply{})
case flags.logFormat != "" && flags.autoApprove:
var (
applied int
plan *migrate.Plan
cause *cmdlog.StmtError
out = cmd.OutOrStdout()
)
if plan, err = client.PlanChanges(ctx, "", changes, planOptions(client)...); err != nil {
return err
}
if err = applyChanges(ctx, client, changes, flags.txMode); err == nil {
applied = len(plan.Changes)
} else if i, ok := err.(interface{ Applied() int }); ok && i.Applied() < len(plan.Changes) {
applied, cause = i.Applied(), &cmdlog.StmtError{Stmt: plan.Changes[i.Applied()].Cmd, Text: err.Error()}
} else {
cause = &cmdlog.StmtError{Text: err.Error()}
}
err1 := format.Execute(out, cmdlog.NewSchemaApply(ctx, cmdlog.NewEnv(client, nil), plan.Changes[:applied], plan.Changes[applied:], cause))
return errors.Join(err, err1)
default:
switch err := summary(cmd, client, changes, format); {
case err != nil:
return err
case flags.dryRun:
return nil
case flags.autoApprove:
return applyChanges(ctx, client, changes, flags.txMode)
default:
return promptApply(cmd, flags, diff, client, dev)
}
}
}
// applySchemaClean is the community-version of the 'atlas schema clean' handler.
func applySchemaClean(cmd *cobra.Command, client *sqlclient.Client, drop []schema.Change, flags schemaCleanFlags) error {
if flags.dryRun {
return AbortErrorf("%s", unsupportedMessage("schema", "clean --dry-run"))
}
if flags.logFormat != "" {
return AbortErrorf("%s", unsupportedMessage("schema", "clean --format"))
}
if len(drop) == 0 {
cmd.Println("Nothing to drop")
return nil
}
if err := summary(cmd, client, drop, cmdlog.SchemaPlanTemplate); err != nil {
return err
}
if flags.autoApprove || promptUser(cmd) {
if err := client.ApplyChanges(cmd.Context(), drop); err != nil {
return err
}
}
return nil
}
func schemaDiffRun(cmd *cobra.Command, _ []string, flags schemaDiffFlags, env *Env) error {
var (
ctx = cmd.Context()
c *sqlclient.Client
)
if len(flags.include) > 0 {
return AbortErrorf("%s", unsupportedMessage("schema", "diff --include"))
}
// We need a driver for diffing and planning. If given, dev database has precedence.
if flags.devURL != "" {
var err error
c, err = sqlclient.Open(ctx, flags.devURL)
if err != nil {
return err
}
defer c.Close()
}
from, err := stateReader(ctx, env, &stateReaderConfig{
urls: flags.fromURL,
dev: c,
vars: env.Vars(),
schemas: flags.schemas,
exclude: flags.exclude,
})
if err != nil {
return err
}
defer from.Close()
to, err := stateReader(ctx, env, &stateReaderConfig{
urls: flags.toURL,
dev: c,
vars: env.Vars(),
schemas: flags.schemas,
exclude: flags.exclude,
})
if err != nil {
return err
}
defer to.Close()
if c == nil {
// If not both states are provided by a database connection, the call to state-reader would have returned
// an error already. If we land in this case, we can assume both states are database connections.
c = to.Closer.(*sqlclient.Client)
}
format := cmdlog.SchemaDiffTemplate
if v := flags.format; v != "" {
if format, err = template.New("format").Funcs(cmdlog.SchemaDiffFuncs).Parse(v); err != nil {
return fmt.Errorf("parse log format: %w", err)
}
}
diff, err := computeDiff(ctx, c, from, to, diffOptions(cmd, env)...)
if err != nil {
return err
}
maySuggestUpgrade(cmd)
return format.Execute(cmd.OutOrStdout(),
cmdlog.NewSchemaDiff(ctx, c, diff.from, diff.to, diff.changes),
)
}
func summary(cmd *cobra.Command, c *sqlclient.Client, changes []schema.Change, t *template.Template) error {
p, err := c.PlanChanges(cmd.Context(), "", changes, planOptions(c)...)
if err != nil {
return err
}
return t.Execute(
cmd.OutOrStdout(),
cmdlog.NewSchemaPlan(cmd.Context(), cmdlog.NewEnv(c, nil), p.Changes, nil),
)
}
func promptApply(cmd *cobra.Command, flags schemaApplyFlags, diff *diff, client, _ *sqlclient.Client) error {
if !flags.dryRun && (flags.autoApprove || promptUser(cmd)) {
return applyChanges(cmd.Context(), client, diff.changes, flags.txMode)
}
return nil
}
func maySetLoginContext(*cobra.Command, *Project) error {
return nil
}
func setEnvs(context.Context, []*Env) {}
// specOptions are the options for the schema spec.
var specOptions []schemahcl.Option
// diffOptions returns environment-aware diff options.
func diffOptions(_ *cobra.Command, env *Env) []schema.DiffOption {
return append(env.DiffOptions(), schema.DiffNormalized())
}
// openClient allows opening environment-aware clients.
func (*Env) openClient(ctx context.Context, u string) (*sqlclient.Client, error) {
return sqlclient.Open(ctx, u)
}
type schemaInspectFlags struct {
url string // URL of resource to inspect.
devURL string // URL of the dev database.
logFormat string // Format of the log output.
schemas []string // Schemas to take into account when diffing.
exclude []string // List of glob patterns used to filter resources from applying (see schema.InspectOptions).
}
// schemaInspectCmd represents the 'atlas schema inspect' subcommand.
func schemaInspectCmd() *cobra.Command {
cmd, _ := schemaInspectCmdWithFlags()
return cmd
}
func schemaInspectCmdWithFlags() (*cobra.Command, *schemaInspectFlags) {
var (
env *Env
flags schemaInspectFlags
cmd = &cobra.Command{
Use: "inspect",
Short: "Inspect a database and print its schema in Atlas DDL syntax.",
Long: `'atlas schema inspect' connects to the given database and inspects its schema.
It then prints to the screen the schema of that database in Atlas DDL syntax. This output can be
saved to a file, commonly by redirecting the output to a file named with a ".hcl" suffix:
atlas schema inspect -u "mysql://user:pass@localhost:3306/dbname" > schema.hcl
This file can then be edited and used with the` + " `atlas schema apply` " + `command to plan
and execute schema migrations against the given database. In cases where users wish to inspect
all multiple schemas in a given database (for instance a MySQL server may contain multiple named
databases), omit the relevant part from the url, e.g. "mysql://user:pass@localhost:3306/".
To select specific schemas from the databases, users may use the "--schema" (or "-s" shorthand)
flag.
`,
Example: ` atlas schema inspect -u "mysql://user:pass@localhost:3306/dbname"
atlas schema inspect -u "mariadb://user:pass@localhost:3306/" --schema=schemaA,schemaB -s schemaC
atlas schema inspect --url "postgres://user:pass@host:port/dbname?sslmode=disable"
atlas schema inspect -u "sqlite://file:ex1.db?_fk=1"`,
PreRunE: RunE(func(cmd *cobra.Command, args []string) (err error) {
if env, err = selectEnv(cmd); err != nil {
return err
}
return setSchemaEnvFlags(cmd, env)
}),
RunE: RunE(func(cmd *cobra.Command, args []string) error {
return schemaInspectRun(cmd, args, flags, env)
}),
}
)
cmd.Flags().SortFlags = false
addFlagURL(cmd.Flags(), &flags.url)
addFlagDevURL(cmd.Flags(), &flags.devURL)
addFlagSchemas(cmd.Flags(), &flags.schemas)
addFlagExclude(cmd.Flags(), &flags.exclude)
addFlagLog(cmd.Flags(), &flags.logFormat)
addFlagFormat(cmd.Flags(), &flags.logFormat)
cobra.CheckErr(cmd.MarkFlagRequired(flagURL))
cmd.MarkFlagsMutuallyExclusive(flagLog, flagFormat)
return cmd, &flags
}
func schemaInspectRun(cmd *cobra.Command, _ []string, flags schemaInspectFlags, env *Env) error {
var (
ctx = cmd.Context()
dev *sqlclient.Client
)
useDev, err := readerUseDev(env, flags.url)
if err != nil {
return err
}
if flags.devURL != "" && useDev {
if dev, err = sqlclient.Open(ctx, flags.devURL); err != nil {
return err
}
defer dev.Close()
}
r, err := stateReader(ctx, env, &stateReaderConfig{
urls: []string{flags.url},
dev: dev,
vars: env.Vars(),
schemas: flags.schemas,
exclude: flags.exclude,
})
if err != nil {
return err
}
defer r.Close()
client, ok := r.Closer.(*sqlclient.Client)
if !ok && dev != nil {
client = dev
}
format := cmdlog.SchemaInspectTemplate
if v := flags.logFormat; v != "" {
if format, err = template.New("format").Funcs(cmdlog.InspectTemplateFuncs).Parse(v); err != nil {
return fmt.Errorf("parse log format: %w", err)
}
}
s, err := r.ReadState(ctx)
if err != nil {
return err
}
maySuggestUpgrade(cmd)
i := cmdlog.NewSchemaInspect(ctx, client, s)
i.URL = flags.url
return format.Execute(cmd.OutOrStdout(), i)
}
================================================
FILE: cmd/atlas/internal/cmdapi/cmdapi_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"bytes"
"context"
"database/sql"
"fmt"
"os"
"testing"
"ariga.io/atlas/sql/sqlite"
"github.com/spf13/cobra"
"github.com/stretchr/testify/require"
)
func TestVars_String(t *testing.T) {
var vs Vars
require.Equal(t, "[]", vs.String())
require.NoError(t, vs.Set("a=b"))
require.Equal(t, "[a:b]", vs.String())
require.NoError(t, vs.Set("b=c"))
require.Equal(t, "[a:b, b:c]", vs.String())
require.NoError(t, vs.Set("a=d"))
require.Equal(t, "[a:[b, d], b:c]", vs.String(), "multiple values of the same key: --var url= --var url=")
}
func runCmd(cmd *cobra.Command, args ...string) (string, error) {
return runCmdContext(context.Background(), cmd, args...)
}
func runCmdContext(ctx context.Context, cmd *cobra.Command, args ...string) (string, error) {
var out bytes.Buffer
cmd.SetOut(&out)
cmd.SetErr(&out)
// Cobra checks for the args to equal nil and if so uses os.Args[1:].
// In tests, this leads to go tooling arguments being part of the command arguments.
if args == nil {
args = []string{}
}
cmd.SetArgs(args)
err := cmd.ExecuteContext(ctx)
return out.String(), err
}
// openSQLite creates a sqlite db, seeds it with the seed query and returns the url to it.
func openSQLite(t *testing.T, seed string) string {
f, err := os.CreateTemp("", "sqlite.db")
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, os.Remove(f.Name()))
})
dsn := fmt.Sprintf("file:%s?cache=shared&_fk=1", f.Name())
db, err := sql.Open("sqlite3", dsn)
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, db.Close())
})
drv, err := sqlite.Open(db)
require.NoError(t, err)
if seed != "" {
_, err := drv.ExecContext(context.Background(), seed)
require.NoError(t, err)
}
return fmt.Sprintf("sqlite://%s", dsn)
}
================================================
FILE: cmd/atlas/internal/cmdapi/migrate.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"bytes"
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"io"
"net/url"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
"strings"
"text/template"
"text/template/parse"
"time"
"ariga.io/atlas/cmd/atlas/internal/cloudapi"
"ariga.io/atlas/cmd/atlas/internal/cmdext"
"ariga.io/atlas/cmd/atlas/internal/cmdlog"
cmdmigrate "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
"ariga.io/atlas/sql/sqltool"
"github.com/google/uuid"
"github.com/spf13/cobra"
)
// migrateCmd represents the subcommand 'atlas migrate'.
func migrateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "migrate",
Short: "Manage versioned migration files",
Long: "'atlas migrate' wraps several sub-commands for migration management.",
}
addGlobalFlags(cmd.PersistentFlags())
return cmd
}
type migrateApplyFlags struct {
url string
dirURL string
revisionSchema string
dryRun bool
logFormat string
lockTimeout time.Duration
allowDirty bool // allow working on a database that already has resources
baselineVersion string // apply with this version as baseline
txMode string // (none, file, all)
execOrder string // (linear, linear-skip, non-linear)
context string // Run context. See cloudapi.DeployContextInput.
}
func (f *migrateApplyFlags) migrateOptions() ([]migrate.ExecutorOption, error) {
var opts []migrate.ExecutorOption
if f.allowDirty {
opts = append(opts, migrate.WithAllowDirty(true))
}
if v := f.baselineVersion; v != "" {
opts = append(opts, migrate.WithBaselineVersion(v))
}
if v := f.execOrder; v != "" && v != execOrderLinear {
switch v {
case execOrderLinearSkip:
opts = append(opts, migrate.WithExecOrder(migrate.ExecOrderLinearSkip))
case execOrderNonLinear:
opts = append(opts, migrate.WithExecOrder(migrate.ExecOrderNonLinear))
default:
return nil, fmt.Errorf("unknown execution order: %q", v)
}
}
return opts, nil
}
func migrateApplyCmd() *cobra.Command {
var (
flags migrateApplyFlags
cmd = &cobra.Command{
Use: "apply [flags] [amount]",
Short: "Applies pending migration files on the connected database.",
Long: `'atlas migrate apply' reads the migration state of the connected database and computes what migrations are pending.
It then attempts to apply the pending migration files in the correct order onto the database.
The first argument denotes the maximum number of migration files to apply.
As a safety measure 'atlas migrate apply' will abort with an error, if:
- the migration directory is not in sync with the 'atlas.sum' file
- the migration and database history do not match each other
If run with the "--dry-run" flag, atlas will not execute any SQL.`,
Example: ` atlas migrate apply -u "mysql://user:pass@localhost:3306/dbname"
atlas migrate apply --dir "file:///path/to/migration/directory" --url "mysql://user:pass@localhost:3306/dbname" 1
atlas migrate apply --env dev 1
atlas migrate apply --dry-run --env dev 1`,
Args: cobra.MaximumNArgs(1),
RunE: RunE(func(cmd *cobra.Command, args []string) (cmdErr error) {
switch {
case GlobalFlags.SelectedEnv == "":
// Env not selected, but the
// -c flag might be set.
env, err := selectEnv(cmd)
if err != nil {
return err
}
if err := setMigrateEnvFlags(cmd, env); err != nil {
return err
}
return migrateApplyRun(cmd, args, flags, env, &MigrateReport{}) // nop reporter
default:
project, envs, err := EnvByName(cmd, GlobalFlags.SelectedEnv, GlobalFlags.Vars)
if err != nil {
return err
}
set, err := NewReportProvider(cmd.Context(), project, envs, &flags)
if err != nil {
return err
}
var hasRemote bool
defer func() {
if hasRemote {
set.Flush(cmd, cmdErr)
}
}()
return cmdEnvsRun(envs, setMigrateEnvFlags, cmd, func(env *Env) error {
// Report deployments only if one of the migration directories is a cloud directory.
if u, err := url.Parse(flags.dirURL); err == nil && u.Scheme == cmdmigrate.DirTypeAtlas {
hasRemote = true
}
return migrateApplyRun(cmd, args, flags, env, set.ReportFor(flags, env))
})
}
}),
}
)
cmd.Flags().SortFlags = false
addFlagURL(cmd.Flags(), &flags.url)
addFlagDirURL(cmd.Flags(), &flags.dirURL)
addFlagLog(cmd.Flags(), &flags.logFormat)
addFlagFormat(cmd.Flags(), &flags.logFormat)
addFlagRevisionSchema(cmd.Flags(), &flags.revisionSchema)
addFlagDryRun(cmd.Flags(), &flags.dryRun)
addFlagLockTimeout(cmd.Flags(), &flags.lockTimeout)
cmd.Flags().StringVarP(&flags.baselineVersion, flagBaseline, "", "", "start the first migration after the given baseline version")
cmd.Flags().StringVarP(&flags.txMode, flagTxMode, "", txModeFile, "set transaction mode [none, file, all]")
cmd.Flags().StringVarP(&flags.execOrder, flagExecOrder, "", execOrderLinear, "set file execution order [linear, linear-skip, non-linear]")
cmd.Flags().StringVar(&flags.context, flagContext, "", "describes what triggered this command (e.g., GitHub Action)")
cobra.CheckErr(cmd.Flags().MarkHidden(flagContext))
cmd.Flags().BoolVarP(&flags.allowDirty, flagAllowDirty, "", false, "allow start working on a non-clean database")
cmd.MarkFlagsMutuallyExclusive(flagLog, flagFormat)
return cmd
}
type (
// MigrateReport responsible for reporting 'migrate apply' reports.
MigrateReport struct {
id string // target id
env *Env // nil, if no env set
client *sqlclient.Client
log *cmdlog.MigrateApply
rrw cmdmigrate.RevisionReadWriter
done func(*cloudapi.ReportMigrationInput)
}
// MigrateReportSet is a set of reports.
MigrateReportSet struct {
cloudapi.ReportMigrationSetInput
client *cloudapi.Client
done int // number of done migrations
}
)
// NewReportProvider returns a new ReporterProvider.
func NewReportProvider(ctx context.Context, p *Project, envs []*Env, flags *migrateApplyFlags) (*MigrateReportSet, error) {
c := cloudapi.FromContext(ctx)
if p.cloud.Client != nil {
c = p.cloud.Client
}
s := &MigrateReportSet{
client: c,
ReportMigrationSetInput: cloudapi.ReportMigrationSetInput{
ID: uuid.NewString(),
StartTime: time.Now(),
Planned: len(envs),
},
}
if flags.context != "" {
if err := json.Unmarshal([]byte(flags.context), &s.Context); err != nil {
return nil, fmt.Errorf("invalid --context: %w", err)
}
}
s.Step("Start migration for %d targets", len(envs))
for _, e := range envs {
s.StepLog(s.RedactedURL(e.URL))
}
return s, nil
}
// RedactedURL returns the redacted URL of the given environment at index i.
func (*MigrateReportSet) RedactedURL(u string) string {
u, err := cloudapi.RedactedURL(u)
if err != nil {
return fmt.Sprintf("Error: redacting URL: %v", err)
}
return u
}
// Step starts a new reporting step.
func (s *MigrateReportSet) Step(format string, args ...interface{}) {
if len(s.Log) > 0 && s.Log[len(s.Log)-1].EndTime.IsZero() {
s.Log[len(s.Log)-1].EndTime = time.Now()
}
s.Log = append(s.Log, cloudapi.ReportStep{
StartTime: time.Now(),
Text: fmt.Sprintf(format, args...),
})
}
// StepLog logs a line to the current reporting step.
func (s *MigrateReportSet) StepLog(text string) {
if len(s.Log) == 0 {
s.Step("Unnamed step") // Unexpected.
}
s.Log[len(s.Log)-1].Log = append(s.Log[len(s.Log)-1].Log, cloudapi.ReportStepLog{
Text: text,
})
}
// StepLogf logs a line to the current reporting step with formatting.
func (s *MigrateReportSet) StepLogf(format string, args ...interface{}) {
s.StepLog(fmt.Sprintf(format, args...))
}
// StepLogError logs a line to the current reporting step.
func (s *MigrateReportSet) StepLogError(text string) {
if !strings.HasPrefix(text, "Error") {
text = "Error: " + text
}
s.StepLog(text)
s.Error = &text
s.Log[len(s.Log)-1].Error = true
}
// ReportFor returns a new MigrateReport for the given environment.
func (s *MigrateReportSet) ReportFor(flags migrateApplyFlags, e *Env) *MigrateReport {
s.Step("Run migration: %d", s.done+1)
s.StepLogf("Target URL: %s", s.RedactedURL(e.URL))
s.StepLogf("Migration directory: %s", s.RedactedURL(flags.dirURL))
return &MigrateReport{
env: e,
done: func(r *cloudapi.ReportMigrationInput) {
s.done++
r.DryRun = flags.dryRun
s.Log[len(s.Log)-1].EndTime = time.Now()
if r.Error != nil && *r.Error != "" {
s.StepLogError(*r.Error)
}
s.Completed = append(s.Completed, *r)
},
}
}
// Flush report the migration deployment to the cloud.
// The current implementation is simplistic and sends each
// report separately without marking them as part of a group.
//
// Note that reporting errors are logged, but not cause Atlas to fail.
func (s *MigrateReportSet) Flush(cmd *cobra.Command, cmdErr error) {
if cmdErr != nil && s.Error == nil {
var uerr *url.Error
if errors.As(cmdErr, &uerr) {
uerr.URL = ""
cmdErr = uerr
}
s.StepLogError(cmdErr.Error())
}
var (
err error
link string
)
switch {
// Skip reporting if set is empty,
// or there is no cloud connectivity.
case s.Planned == 0, s.client == nil:
return
// Single migration that was completed.
case s.Planned == 1 && len(s.Completed) == 1:
s.Completed[0].Context = s.Context
link, err = s.client.ReportMigration(cmd.Context(), s.Completed[0])
// Single migration that failed to start.
case s.Planned == 1 && len(s.Completed) == 0:
s.EndTime = time.Now()
link, err = s.client.ReportMigrationSet(cmd.Context(), s.ReportMigrationSetInput)
// Multi environment migration (e.g., multi-tenancy).
case s.Planned > 1:
s.EndTime = time.Now()
link, err = s.client.ReportMigrationSet(cmd.Context(), s.ReportMigrationSetInput)
}
switch {
case err != nil:
txt := fmt.Sprintf("Error: %s", strings.TrimRight(err.Error(), "\n"))
// Ensure errors are printed in new lines.
if cmd.Flags().Changed(flagFormat) {
txt = "\n" + txt
}
cmd.PrintErrln(txt)
// Unlike errors that are printed to stderr, links are printed to stdout.
// We do it only if the format was not customized by the user (e.g., JSON).
case link != "" && !cmd.Flags().Changed(flagFormat):
cmd.Println(link)
}
}
// Init the report if the necessary dependencies.
func (r *MigrateReport) Init(c *sqlclient.Client, l *cmdlog.MigrateApply, rrw cmdmigrate.RevisionReadWriter) {
r.client, r.log, r.rrw = c, l, rrw
}
// RecordTargetID asks the revisions-table to allow or provide
// the target identifier if cloud reporting is enabled.
func (r *MigrateReport) RecordTargetID(ctx context.Context) error {
if r.CloudEnabled(ctx) {
id, err := r.rrw.ID(ctx, operatorVersion())
if err != nil {
return err
}
r.id = id
}
return nil
}
// RecordPlanError records any errors that occurred during the planning phase. i.e., when calling to ex.Pending.
func (r *MigrateReport) RecordPlanError(cmd *cobra.Command, flags migrateApplyFlags, planerr string) {
if !r.CloudEnabled(cmd.Context()) {
return
}
var ver string
if rev, err := r.rrw.CurrentRevision(cmd.Context()); err == nil {
ver = rev.Version
}
r.done(&cloudapi.ReportMigrationInput{
ProjectName: r.env.config.cloud.Project,
EnvName: r.env.Name,
DirName: r.DirName(flags),
AtlasVersion: operatorVersion(),
Target: cloudapi.DeployedTargetInput{
ID: r.id,
Schema: r.client.URL.Schema,
URL: r.client.URL.Redacted(),
},
StartTime: r.log.Start,
EndTime: r.log.End,
FromVersion: r.log.Current,
ToVersion: r.log.Target,
CurrentVersion: ver,
Error: &planerr,
Log: planerr,
})
}
// Done closes and flushes this report.
func (r *MigrateReport) Done(cmd *cobra.Command, flags migrateApplyFlags) error {
if !r.CloudEnabled(cmd.Context()) {
return logApply(cmd, cmd.OutOrStdout(), flags, r.log)
}
var (
ver string
clog bytes.Buffer
err = logApply(cmd, io.MultiWriter(cmd.OutOrStdout(), &clog), flags, r.log)
)
switch rev, err1 := r.rrw.CurrentRevision(cmd.Context()); {
case errors.Is(err1, migrate.ErrRevisionNotExist):
case err1 != nil:
return errors.Join(err, err1)
default:
ver = rev.Version
}
r.done(&cloudapi.ReportMigrationInput{
ProjectName: r.env.config.cloud.Project,
EnvName: r.env.Name,
DirName: r.DirName(flags),
AtlasVersion: operatorVersion(),
Target: cloudapi.DeployedTargetInput{
ID: r.id,
Schema: r.client.URL.Schema,
URL: r.client.URL.Redacted(),
},
StartTime: r.log.Start,
EndTime: r.log.End,
FromVersion: r.log.Current,
ToVersion: r.log.Target,
CurrentVersion: ver,
Error: func() *string {
if r.log.Error != "" {
return &r.log.Error
}
return nil
}(),
Files: func() []cloudapi.DeployedFileInput {
files := make([]cloudapi.DeployedFileInput, len(r.log.Applied))
for i, f := range r.log.Applied {
f1 := cloudapi.DeployedFileInput{
Name: f.Name(),
Content: string(f.Bytes()),
StartTime: f.Start,
EndTime: f.End,
Skipped: f.Skipped,
Applied: len(f.Applied),
Error: (*cloudapi.StmtErrorInput)(f.Error),
Checks: make([]cloudapi.FileChecksInput, 0, len(f.Checks)),
}
for _, c := range f.Checks {
stmts := make([]cloudapi.CheckStmtInput, 0, len(c.Stmts))
for _, s := range c.Stmts {
stmts = append(stmts, cloudapi.CheckStmtInput{
Stmt: s.Stmt,
Error: s.Error,
})
}
f1.Checks = append(f1.Checks, cloudapi.FileChecksInput{
Name: c.Name,
Start: c.Start,
End: c.End,
Checks: stmts,
Error: (*cloudapi.StmtErrorInput)(c.Error),
})
}
files[i] = f1
}
return files
}(),
Log: clog.String(),
})
return err
}
// DirName returns the directory name for the report.
func (r *MigrateReport) DirName(flags migrateApplyFlags) string {
dirName := flags.dirURL
switch u, err := url.Parse(flags.dirURL); {
case err != nil:
// Local directories are reported as (dangling)
// deployments without a directory.
case u.Scheme == cmdmigrate.DirTypeFile:
dirName = cloudapi.DefaultDirName
// Directory slug.
default:
dirName = path.Join(u.Host, u.Path)
}
return dirName
}
// CloudEnabled reports if cloud reporting is enabled.
func (r *MigrateReport) CloudEnabled(ctx context.Context) bool {
if r.env == nil || r.env.cloud == nil {
return false // The --env was not set.
}
cloud := r.env.cloud
// Cloud reporting is enabled only if there is a cloud connection.
return cloud.Project != "" && (cloud.Client != nil || cloudapi.FromContext(ctx) != nil)
}
func logApply(cmd *cobra.Command, w io.Writer, flags migrateApplyFlags, r *cmdlog.MigrateApply) error {
var (
err error
f = cmdlog.MigrateApplyTemplate
)
if v := flags.logFormat; v != "" {
f, err = template.New("format").Funcs(cmdlog.ApplyTemplateFuncs).Parse(v)
if err != nil {
return fmt.Errorf("parse format: %w", err)
}
}
if err = f.Execute(w, r); err != nil {
return fmt.Errorf("execute log template: %w", err)
}
// In case a custom logging was configured, avoid reporting errors twice.
// For example, printing error lines may break parsing the JSON output.
cmd.SilenceErrors = flags.logFormat != ""
return nil
}
type migrateDiffFlags struct {
edit bool
desiredURLs []string
dirURL, dirFormat string
devURL string
schemas []string
lockTimeout time.Duration
format string
qualifier string // optional table qualifier
dryRun bool
}
// migrateDiffCmd represents the 'atlas migrate diff' subcommand.
func migrateDiffCmd() *cobra.Command {
var (
flags migrateDiffFlags
cmd = &cobra.Command{
Use: "diff [flags] [name]",
Short: "Compute the diff between the migration directory and a desired state and create a new migration file.",
Long: `The 'atlas migrate diff' command uses the dev-database to calculate the current state of the migration directory
by executing its files. It then compares its state to the desired state and create a new migration file containing
SQL statements for moving from the current to the desired state. The desired state can be another another database,
an HCL, SQL, or ORM schema. See: https://atlasgo.io/versioned/diff`,
Example: ` atlas migrate diff --dev-url "docker://mysql/8/dev" --to "file://schema.hcl"
atlas migrate diff --dev-url "docker://postgres/15/dev?search_path=public" --to "file://atlas.hcl" add_users_table
atlas migrate diff --dev-url "mysql://user:pass@localhost:3306/dev" --to "mysql://user:pass@localhost:3306/dbname"
atlas migrate diff --env dev --format '{{ sql . " " }}'`,
Args: cobra.MaximumNArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
if err := migrateFlagsFromConfig(cmd); err != nil {
return err
}
if err := dirFormatBC(flags.dirFormat, &flags.dirURL); err != nil {
return err
}
return checkDir(cmd, flags.dirURL, true)
},
RunE: RunE(func(cmd *cobra.Command, args []string) error {
env, err := selectEnv(cmd)
if err != nil {
return err
}
return migrateDiffRun(cmd, args, flags, env)
}),
}
)
cmd.Flags().SortFlags = false
addFlagToURLs(cmd.Flags(), &flags.desiredURLs)
addFlagDevURL(cmd.Flags(), &flags.devURL)
addFlagDirURL(cmd.Flags(), &flags.dirURL)
addFlagDirFormat(cmd.Flags(), &flags.dirFormat)
addFlagSchemas(cmd.Flags(), &flags.schemas)
addFlagLockTimeout(cmd.Flags(), &flags.lockTimeout)
addFlagFormat(cmd.Flags(), &flags.format)
cmd.Flags().StringVar(&flags.qualifier, flagQualifier, "", "qualify tables with custom qualifier when working on a single schema")
cmd.Flags().BoolVarP(&flags.edit, flagEdit, "", false, "edit the generated migration file(s)")
cmd.Flags().BoolVar(&flags.dryRun, flagDryRun, false, "print the generated file to stdout instead of writing it to the migration directory")
cobra.CheckErr(cmd.Flags().MarkHidden(flagDryRun))
cmd.MarkFlagsMutuallyExclusive(flagEdit, flagDryRun)
cobra.CheckErr(cmd.MarkFlagRequired(flagTo))
cobra.CheckErr(cmd.MarkFlagRequired(flagDevURL))
return cmd
}
func mayIndent(dir *url.URL, f migrate.Formatter, format string) (migrate.Formatter, string, error) {
if format == "" {
return f, "", nil
}
reject := errors.New(`'sql' can only be used to indent statements`)
t, err := template.New("format").
// The "sql" is a dummy function to detect if the
// template was used to indent the SQL statements.
Funcs(template.FuncMap{"sql": func(...any) (string, error) { return "", reject }}).
Parse(format)
if err != nil {
return nil, "", fmt.Errorf("parse format: %w", err)
}
indent, ok := func() (string, bool) {
if len(t.Tree.Root.Nodes) != 1 {
return "", false
}
n, ok := t.Tree.Root.Nodes[0].(*parse.ActionNode)
if !ok || len(n.Pipe.Cmds) != 1 || len(n.Pipe.Cmds[0].Args) < 2 || len(n.Pipe.Cmds[0].Args) > 3 {
return "", false
}
args := n.Pipe.Cmds[0].Args
if args[0].String() != "sql" || args[1].String() != "." && args[1].String() != "$" {
return "", false
}
d := `""` // empty string as arg.
if len(args) == 3 {
d = args[2].String()
}
return d, true
}()
if ok {
if indent, err = strconv.Unquote(indent); err != nil {
return nil, "", fmt.Errorf("parse indent: %w", err)
}
return f, indent, nil
}
// If the template is not an indent, it cannot contain the "sql" function.
if err := t.Execute(io.Discard, &migrate.Plan{}); err != nil && errors.Is(err, reject) {
return nil, "", fmt.Errorf("%v. got: %v", reject, t.Root.String())
}
tfs := f.(migrate.TemplateFormatter)
if len(tfs) != 1 {
return nil, "", fmt.Errorf("cannot use format with: %q", dir.Query().Get("format"))
}
return migrate.TemplateFormatter{{N: tfs[0].N, C: t}}, "", nil
}
// maskNoPlan masks ErrNoPlan errors.
func maskNoPlan(cmd *cobra.Command, err error) error {
if errors.Is(err, migrate.ErrNoPlan) {
cmd.Println("The migration directory is synced with the desired state, no changes to be made")
return nil
}
return err
}
type migrateHashFlags struct{ dirURL, dirFormat string }
// migrateHashCmd represents the 'atlas migrate hash' subcommand.
func migrateHashCmd() *cobra.Command {
var (
flags migrateHashFlags
cmd = &cobra.Command{
Use: "hash [flags]",
Short: "Hash (re-)creates an integrity hash file for the migration directory.",
Long: `'atlas migrate hash' computes the integrity hash sum of the migration directory and stores it in the atlas.sum file.
This command should be used whenever a manual change in the migration directory was made.`,
Example: ` atlas migrate hash`,
PreRunE: func(cmd *cobra.Command, args []string) error {
if err := migrateFlagsFromConfig(cmd); err != nil {
return err
}
return dirFormatBC(flags.dirFormat, &flags.dirURL)
},
RunE: RunE(func(cmd *cobra.Command, args []string) error {
dir, err := cmdmigrate.Dir(cmd.Context(), flags.dirURL, false)
if err != nil {
return err
}
sum, err := dir.Checksum()
if err != nil {
return err
}
return migrate.WriteSumFile(dir, sum)
}),
}
)
addFlagDirURL(cmd.Flags(), &flags.dirURL)
addFlagDirFormat(cmd.Flags(), &flags.dirFormat)
cmd.Flags().Bool("force", false, "")
cobra.CheckErr(cmd.Flags().MarkDeprecated("force", "you can safely omit it."))
return cmd
}
type migrateImportFlags struct{ fromURL, toURL, dirFormat string }
// migrateImportCmd represents the 'atlas migrate import' subcommand.
func migrateImportCmd() *cobra.Command {
var (
flags migrateImportFlags
cmd = &cobra.Command{
Use: "import [flags]",
Short: "Import a migration directory from another migration management tool to the Atlas format.",
Example: ` atlas migrate import --from "file:///path/to/source/directory?format=liquibase" --to "file:///path/to/migration/directory"`,
// Validate the source directory. Consider a directory with no sum file
// valid, since it might be an import from an existing project.
PreRunE: func(cmd *cobra.Command, _ []string) error {
if err := migrateFlagsFromConfig(cmd); err != nil {
return err
}
if err := dirFormatBC(flags.dirFormat, &flags.fromURL); err != nil {
return err
}
d, err := cmdmigrate.Dir(cmd.Context(), flags.fromURL, false)
if err != nil {
return err
}
if err = migrate.Validate(d); err != nil && !errors.Is(err, migrate.ErrChecksumNotFound) {
printChecksumError(cmd, err)
return err
}
return nil
},
RunE: RunE(func(cmd *cobra.Command, args []string) error {
return migrateImportRun(cmd, args, flags)
}),
}
)
cmd.Flags().SortFlags = false
addFlagDirURL(cmd.Flags(), &flags.fromURL, flagFrom)
addFlagDirURL(cmd.Flags(), &flags.toURL, flagTo)
addFlagDirFormat(cmd.Flags(), &flags.dirFormat)
return cmd
}
func migrateImportRun(cmd *cobra.Command, _ []string, flags migrateImportFlags) error {
p, err := url.Parse(flags.fromURL)
if err != nil {
return err
}
if f := p.Query().Get("format"); f == "" || f == cmdmigrate.FormatAtlas {
return fmt.Errorf("cannot import a migration directory already in %q format", cmdmigrate.FormatAtlas)
}
src, err := cmdmigrate.Dir(cmd.Context(), flags.fromURL, false)
if err != nil {
return err
}
trgt, err := cmdmigrate.Dir(cmd.Context(), flags.toURL, true)
if err != nil {
return err
}
// Target must be empty.
ff, err := trgt.Files()
switch {
case err != nil:
return err
case len(ff) != 0:
return errors.New("target migration directory must be empty")
}
ff, err = src.Files()
switch {
case err != nil:
return err
case len(ff) == 0:
fmt.Fprint(cmd.OutOrStderr(), "nothing to import")
cmd.SilenceUsage = true
return nil
}
// Fix version numbers for Flyway repeatable migrations.
if _, ok := src.(*sqltool.FlywayDir); ok {
sqltool.SetRepeatableVersion(ff)
}
// Extract the statements for each of the migration files,
// add them to a plan to format with the DefaultFormatter.
for _, f := range ff {
stmts, err := f.StmtDecls() // Not driver aware.
if err != nil {
return err
}
plan := &migrate.Plan{
Version: f.Version(),
Name: f.Desc(),
Changes: make([]*migrate.Change, len(stmts)),
}
var buf strings.Builder
for i, s := range stmts {
for _, c := range s.Comments {
buf.WriteString(c)
if !strings.HasSuffix(c, "\n") {
buf.WriteString("\n")
}
}
buf.WriteString(strings.TrimSuffix(s.Text, ";"))
plan.Changes[i] = &migrate.Change{Cmd: buf.String()}
buf.Reset()
}
files, err := migrate.DefaultFormatter.Format(plan)
if err != nil {
return err
}
for _, f := range files {
if err := trgt.WriteFile(f.Name(), f.Bytes()); err != nil {
return err
}
}
}
sum, err := trgt.Checksum()
if err != nil {
return err
}
return migrate.WriteSumFile(trgt, sum)
}
type migrateLintFlags struct {
dirURL, dirFormat string
devURL string
logFormat string
latest uint // --latest 1
gitBase, gitDir string // --git-base master --git-dir /path/to/git/repo
// Not enabled by default.
dirBase string // --base atlas://myapp
web bool // Open the web browser
context string // Run context. See cloudapi.ContextInput.
}
// migrateLintCmd represents the 'atlas migrate lint' subcommand.
func migrateLintCmd() *cobra.Command {
var (
env *Env
flags migrateLintFlags
cmd = &cobra.Command{
Use: "lint [flags]",
Short: "Run analysis on the migration directory",
Example: ` atlas migrate lint --env dev
atlas migrate lint --dir "file:///path/to/migrations" --dev-url "docker://mysql/8/dev" --latest 1
atlas migrate lint --dir "file:///path/to/migrations" --dev-url "mysql://root:pass@localhost:3306" --git-base master
atlas migrate lint --dir "file:///path/to/migrations" --dev-url "mysql://root:pass@localhost:3306" --format '{{ json .Files }}'`,
PreRunE: func(cmd *cobra.Command, args []string) (err error) {
if env, err = selectEnv(cmd); err != nil {
return err
}
if err := setMigrateEnvFlags(cmd, env); err != nil {
return err
}
return dirFormatBC(flags.dirFormat, &flags.dirURL)
},
RunE: RunE(func(cmd *cobra.Command, args []string) error {
return migrateLintRun(cmd, args, flags, env)
}),
}
)
cmd.Flags().SortFlags = false
addFlagDevURL(cmd.Flags(), &flags.devURL)
addFlagDirURL(cmd.Flags(), &flags.dirURL)
addFlagDirFormat(cmd.Flags(), &flags.dirFormat)
addFlagLog(cmd.Flags(), &flags.logFormat)
addFlagFormat(cmd.Flags(), &flags.logFormat)
cmd.Flags().UintVarP(&flags.latest, flagLatest, "", 0, "run analysis on the latest N migration files")
cmd.Flags().StringVarP(&flags.gitBase, flagGitBase, "", "", "run analysis against the base Git branch")
cmd.Flags().StringVarP(&flags.gitDir, flagGitDir, "", ".", "path to the repository working directory")
cobra.CheckErr(cmd.MarkFlagRequired(flagDevURL))
cmd.MarkFlagsMutuallyExclusive(flagLog, flagFormat)
migrateLintSetFlags(cmd, &flags)
return cmd
}
type migrateNewFlags struct {
edit bool
dirURL string
dirFormat string
}
// migrateNewCmd represents the 'atlas migrate new' subcommand.
func migrateNewCmd() *cobra.Command {
var (
flags migrateNewFlags
cmd = &cobra.Command{
Use: "new [flags] [name]",
Short: "Creates a new empty migration file in the migration directory.",
Long: `'atlas migrate new' creates a new migration according to the configured formatter without any statements in it.`,
Example: ` atlas migrate new my-new-migration`,
Args: cobra.MaximumNArgs(1),
PreRunE: func(cmd *cobra.Command, _ []string) error {
if err := migrateFlagsFromConfig(cmd); err != nil {
return err
}
if err := dirFormatBC(flags.dirFormat, &flags.dirURL); err != nil {
return err
}
return checkDir(cmd, flags.dirURL, true)
},
RunE: RunE(func(cmd *cobra.Command, args []string) error {
return migrateNewRun(cmd, args, flags)
}),
}
)
cmd.Flags().SortFlags = false
addFlagDirURL(cmd.Flags(), &flags.dirURL)
addFlagDirFormat(cmd.Flags(), &flags.dirFormat)
cmd.Flags().BoolVarP(&flags.edit, flagEdit, "", false, "edit the created migration file(s)")
return cmd
}
func migrateNewRun(cmd *cobra.Command, args []string, flags migrateNewFlags) error {
u, err := url.Parse(flags.dirURL)
if err != nil {
return err
}
dir, err := cmdmigrate.DirURL(cmd.Context(), u, true)
if err != nil {
return err
}
if flags.edit {
l, ok := dir.(*migrate.LocalDir)
if !ok {
return fmt.Errorf("--edit flag supports only atlas directories, but got: %T", dir)
}
dir = &editDir{l}
}
f, err := cmdmigrate.Formatter(u)
if err != nil {
return err
}
var name string
if len(args) > 0 {
name = args[0]
}
return migrate.NewPlanner(nil, dir, migrate.PlanFormat(f)).WritePlan(&migrate.Plan{Name: name})
}
type migrateSetFlags struct {
url string
dirURL, dirFormat string
revisionSchema string
}
// migrateSetCmd represents the 'atlas migrate set' subcommand.
func migrateSetCmd() *cobra.Command {
var (
flags migrateSetFlags
cmd = &cobra.Command{
Use: "set [flags] [version]",
Short: "Set the current version of the migration history table.",
Long: `'atlas migrate set' edits the revision table to consider all migrations up to and including the given version
to be applied. This command is usually used after manually making changes to the managed database.`,
Example: ` atlas migrate set 3 --url "mysql://user:pass@localhost:3306/"
atlas migrate set --env local
atlas migrate set 1.2.4 --url "mysql://user:pass@localhost:3306/my_db" --revision-schema my_revisions`,
PreRunE: func(cmd *cobra.Command, _ []string) error {
if err := migrateFlagsFromConfig(cmd); err != nil {
return err
}
if err := dirFormatBC(flags.dirFormat, &flags.dirURL); err != nil {
return err
}
return checkDir(cmd, flags.dirURL, false)
},
RunE: RunE(func(cmd *cobra.Command, args []string) error {
return migrateSetRun(cmd, args, flags)
}),
}
)
cmd.Flags().SortFlags = false
addFlagURL(cmd.Flags(), &flags.url)
addFlagDirURL(cmd.Flags(), &flags.dirURL)
addFlagDirFormat(cmd.Flags(), &flags.dirFormat)
addFlagRevisionSchema(cmd.Flags(), &flags.revisionSchema)
return cmd
}
func migrateSetRun(cmd *cobra.Command, args []string, flags migrateSetFlags) (rerr error) {
ctx := cmd.Context()
dir, err := cmdmigrate.Dir(ctx, flags.dirURL, false)
if err != nil {
return err
}
client, err := sqlclient.Open(ctx, flags.url)
if err != nil {
return err
}
defer client.Close()
// Acquire a lock.
unlock, err := client.Driver.Lock(ctx, applyLockValue, 0)
if err != nil {
return fmt.Errorf("acquiring database lock: %w", err)
}
// If unlocking fails notify the user about it.
defer func() { cobra.CheckErr(unlock()) }()
if err := checkRevisionSchemaClarity(cmd, client, flags.revisionSchema); err != nil {
return err
}
// Ensure revision table exists.
rrw, err := entRevisions(ctx, client, flags.revisionSchema)
if err != nil {
return err
}
if err := rrw.Migrate(ctx); err != nil {
return err
}
// Wrap manipulation in a transaction.
tx, err := client.Tx(ctx, nil)
if err != nil {
return err
}
defer func() {
if rerr == nil {
rerr = tx.Commit()
} else if err2 := tx.Rollback(); err2 != nil {
rerr = fmt.Errorf("%v: %w", err2, err)
}
}()
rrw, err = entRevisions(ctx, tx.Client, flags.revisionSchema)
if err != nil {
return err
}
revs, err := rrw.ReadRevisions(ctx)
if err != nil {
return err
}
files, err := dir.Files()
if err != nil {
return err
}
var version string
switch n := len(args); {
// Prevent the case where 'migrate set' is called without a version on
// a clean database. i.e., we allow only removing or syncing revisions.
case n == 0 && len(revs) > 0:
// Calling set without a version and an empty
// migration directory purges the revision table.
if len(files) > 0 {
version = files[len(files)-1].Version()
}
case n == 1:
// Check if the target version does exist in the migration directory.
if idx := migrate.FilesLastIndex(files, func(f migrate.File) bool {
return f.Version() == args[0]
}); idx == -1 {
return fmt.Errorf("migration with version %q not found", args[0])
}
version = args[0]
default:
return fmt.Errorf("accepts 1 arg(s), received %d", n)
}
log := cmdlog.NewMigrateSet(ctx)
for _, r := range revs {
// Check all existing revisions and ensure they precede the given version. If we encounter a partially
// applied revision, or one with errors, mark them "fixed".
switch {
// remove revision to keep linear history
case r.Version > version:
log.Removed(r)
if err := rrw.DeleteRevision(ctx, r.Version); err != nil {
return err
}
// keep, but if with error mark "fixed"
case r.Version == version && (r.Error != "" || r.Total != r.Applied):
log.Set(r)
r.Type = migrate.RevisionTypeExecute | migrate.RevisionTypeResolved
if err := rrw.WriteRevision(ctx, r); err != nil {
return err
}
}
}
revs, err = rrw.ReadRevisions(ctx)
if err != nil {
return err
}
// If the target version succeeds the last revision, mark
// migrations applied, until we reach the target version.
var pending []migrate.File
switch {
case len(revs) == 0:
// Take every file until we reach target version.
for _, f := range files {
if f.Version() > version {
break
}
pending = append(pending, f)
}
case version > revs[len(revs)-1].Version:
loop:
// Take every file succeeding the last revision until we reach target version.
for _, f := range files {
switch {
case f.Version() <= revs[len(revs)-1].Version:
// Migration precedes last revision.
case f.Version() > version:
// Migration succeeds target revision.
break loop
default: // between last revision and target
pending = append(pending, f)
}
}
}
// Mark every pending file as applied.
sum, err := dir.Checksum()
if err != nil {
return err
}
for _, f := range pending {
h, err := sum.SumByName(f.Name())
if err != nil {
return err
}
rev := &migrate.Revision{
Version: f.Version(),
Description: f.Desc(),
Type: migrate.RevisionTypeResolved,
ExecutedAt: time.Now(),
Hash: h,
OperatorVersion: operatorVersion(),
}
log.Set(rev)
if err := rrw.WriteRevision(ctx, rev); err != nil {
return err
}
}
if log.Current, err = rrw.CurrentRevision(ctx); err != nil && !errors.Is(err, migrate.ErrRevisionNotExist) {
return err
}
return cmdlog.MigrateSetTemplate.Execute(cmd.OutOrStdout(), log)
}
type migrateStatusFlags struct {
url string
dirURL, dirFormat string
revisionSchema string
logFormat string
}
// migrateStatusCmd represents the 'atlas migrate status' subcommand.
func migrateStatusCmd() *cobra.Command {
var (
flags migrateStatusFlags
cmd = &cobra.Command{
Use: "status [flags]",
Short: "Get information about the current migration status.",
Long: `'atlas migrate status' reports information about the current status of a connected database compared to the migration directory.`,
Example: ` atlas migrate status --url "mysql://user:pass@localhost:3306/"
atlas migrate status --url "mysql://user:pass@localhost:3306/" --dir "file:///path/to/migration/directory"`,
PreRunE: func(cmd *cobra.Command, _ []string) error {
if err := migrateFlagsFromConfig(cmd); err != nil {
return err
}
if err := dirFormatBC(flags.dirFormat, &flags.dirURL); err != nil {
return err
}
return checkDir(cmd, flags.dirURL, false)
},
RunE: RunE(func(cmd *cobra.Command, args []string) error {
return migrateStatusRun(cmd, args, flags)
}),
}
)
cmd.Flags().SortFlags = false
addFlagURL(cmd.Flags(), &flags.url)
addFlagLog(cmd.Flags(), &flags.logFormat)
addFlagFormat(cmd.Flags(), &flags.logFormat)
addFlagDirURL(cmd.Flags(), &flags.dirURL)
addFlagDirFormat(cmd.Flags(), &flags.dirFormat)
addFlagRevisionSchema(cmd.Flags(), &flags.revisionSchema)
cmd.MarkFlagsMutuallyExclusive(flagLog, flagFormat)
return cmd
}
func migrateStatusRun(cmd *cobra.Command, _ []string, flags migrateStatusFlags) error {
ctx := cmd.Context()
dirURL, err := url.Parse(flags.dirURL)
if err != nil {
return fmt.Errorf("parse dir-url: %w", err)
}
dir, err := cmdmigrate.DirURL(ctx, dirURL, false)
if err != nil {
return err
}
client, err := sqlclient.Open(ctx, flags.url)
if err != nil {
return err
}
defer client.Close()
if err := checkRevisionSchemaClarity(cmd, client, flags.revisionSchema); err != nil {
return err
}
report, err := (&cmdlog.StatusReporter{
Client: client,
Dir: dir,
DirURL: dirURL,
Schema: revisionSchemaName(client, flags.revisionSchema),
}).Report(ctx)
if err != nil {
return err
}
format := cmdlog.MigrateStatusTemplate
if f := flags.logFormat; f != "" {
if format, err = template.New("format").Funcs(cmdlog.StatusTemplateFuncs).Parse(f); err != nil {
return fmt.Errorf("parse format: %w", err)
}
}
return format.Execute(cmd.OutOrStdout(), report)
}
type migrateValidateFlags struct {
devURL string
dirURL, dirFormat string
}
// migrateValidateCmd represents the 'atlas migrate validate' subcommand.
func migrateValidateCmd() *cobra.Command {
var (
flags migrateValidateFlags
cmd = &cobra.Command{
Use: "validate [flags]",
Short: "Validates the migration directories checksum and SQL statements.",
Long: `'atlas migrate validate' computes the integrity hash sum of the migration directory and compares it to the
atlas.sum file. If there is a mismatch it will be reported. If the --dev-url flag is given, the migration
files are executed on the connected database in order to validate SQL semantics.`,
Example: ` atlas migrate validate
atlas migrate validate --dir "file:///path/to/migration/directory"
atlas migrate validate --dir "file:///path/to/migration/directory" --dev-url "docker://mysql/8/dev"
atlas migrate validate --env dev --dev-url "docker://postgres/15/dev?search_path=public"`,
PreRunE: func(cmd *cobra.Command, _ []string) error {
if err := migrateFlagsFromConfig(cmd); err != nil {
return err
}
if err := dirFormatBC(flags.dirFormat, &flags.dirURL); err != nil {
return err
}
err := checkDir(cmd, flags.dirURL, false)
return err
},
RunE: RunE(func(cmd *cobra.Command, args []string) error {
return migrateValidateRun(cmd, args, flags)
}),
}
)
cmd.Flags().SortFlags = false
addFlagDevURL(cmd.Flags(), &flags.devURL)
addFlagDirURL(cmd.Flags(), &flags.dirURL)
addFlagDirFormat(cmd.Flags(), &flags.dirFormat)
return cmd
}
func migrateValidateRun(cmd *cobra.Command, _ []string, flags migrateValidateFlags) error {
// Validating the integrity is done by the PersistentPreRun already.
if flags.devURL == "" {
// If there is no --dev-url given do not attempt to replay the migration directory.
return nil
}
// Open a client for the dev-db.
dev, err := sqlclient.Open(cmd.Context(), flags.devURL)
if err != nil {
return err
}
defer dev.Close()
// Currently, only our own migration file format is supported.
dir, err := cmdmigrate.Dir(cmd.Context(), flags.dirURL, false)
if err != nil {
return err
}
ex, err := migrate.NewExecutor(dev.Driver, dir, migrate.NopRevisionReadWriter{})
if err != nil {
return err
}
if _, err := ex.Replay(cmd.Context(), func() migrate.StateReader {
if dev.URL.Schema != "" {
return migrate.SchemaConn(dev, "", nil)
}
return migrate.RealmConn(dev, nil)
}()); err != nil && !errors.Is(err, migrate.ErrNoPendingFiles) {
return fmt.Errorf("replaying the migration directory: %w", err)
}
return nil
}
const applyLockValue = "atlas_migrate_execute"
func checkRevisionSchemaClarity(cmd *cobra.Command, c *sqlclient.Client, revisionSchemaFlag string) error {
// The "old" default behavior for the revision schema location was to store the revision table in its own schema.
// Now, the table is saved in the connected schema, if any. To keep the backwards compatability, we now require
// for schema bound connections to have the schema-revision flag present if there is no revision table in the schema
// but the old default schema does have one.
if c.URL.Schema != "" && revisionSchemaFlag == "" {
// If the schema does not contain a revision table, but we can find a table in the previous default schema,
// abort and tell the user to specify the intention.
opts := &schema.InspectOptions{Tables: []string{revision.Table}, Mode: schema.InspectTables}
s, err := c.InspectSchema(cmd.Context(), "", opts)
var ok bool
switch {
case schema.IsNotExistError(err):
// If the schema does not exist, the table does not as well.
case err != nil:
return err
default:
// Connected schema does exist, check if the table does.
_, ok = s.Table(revision.Table)
}
if !ok { // Either schema or table does not exist.
// Check for the old default schema. If it does not exist, we have no problem.
s, err := c.InspectSchema(cmd.Context(), defaultRevisionSchema, opts)
switch {
case schema.IsNotExistError(err):
// Schema does not exist, we can proceed.
case err != nil:
return err
default:
if _, ok := s.Table(revision.Table); ok {
fmt.Fprintf(cmd.OutOrStderr(),
`We couldn't find a revision table in the connected schema but found one in
the schema 'atlas_schema_revisions' and cannot determine the desired behavior.
As a safety guard, we require you to specify whether to use the existing
table in 'atlas_schema_revisions' or create a new one in the connected schema
by providing the '--revisions-schema' flag or deleting the 'atlas_schema_revisions'
schema if it is unused.
`)
cmd.SilenceUsage = true
cmd.SilenceErrors = true
return errors.New("ambiguous revision table")
}
}
}
}
return nil
}
func entRevisions(ctx context.Context, c *sqlclient.Client, flag string) (cmdmigrate.RevisionReadWriter, error) {
return cmdmigrate.RevisionsForClient(ctx, c, revisionSchemaName(c, flag))
}
// defaultRevisionSchema is the default schema for storing revisions table.
const defaultRevisionSchema = "atlas_schema_revisions"
func revisionSchemaName(c *sqlclient.Client, flag string) string {
switch {
case flag != "":
return flag
case c.URL.Schema != "":
return c.URL.Schema
default:
return defaultRevisionSchema
}
}
const (
txModeNone = "none"
txModeAll = "all"
txModeFile = "file"
txModeDirective = "txmode"
execOrderLinear = "linear"
execOrderLinearSkip = "linear-skip"
execOrderNonLinear = "non-linear"
)
// tx handles wrapping migration execution in transactions.
type tx struct {
dryRun bool
mode, schema string
c *sqlclient.Client
rrw migrate.RevisionReadWriter
// current transaction context.
tx *sqlclient.TxClient
txrrw migrate.RevisionReadWriter
}
// driverFor returns the migrate.Driver to use to execute migration statements.
func (tx *tx) driverFor(ctx context.Context, f migrate.File) (migrate.Driver, migrate.RevisionReadWriter, error) {
if tx.dryRun {
// If the --dry-run flag is given we don't want to execute any statements on the database.
return &dryRunDriver{tx.c.Driver}, &dryRunRevisions{tx.rrw}, nil
}
mode, err := tx.modeFor(f)
if err != nil {
return nil, nil, err
}
switch mode {
case txModeNone:
return tx.c.Driver, tx.rrw, nil
case txModeFile:
// In file-mode, this function is called each time a new file is executed. Open a transaction.
if tx.tx != nil {
return nil, nil, errors.New("unexpected active transaction")
}
var err error
tx.tx, err = tx.c.Tx(ctx, nil)
if err != nil {
return nil, nil, err
}
if tx.txrrw, err = entRevisions(ctx, tx.tx.Client, tx.schema); err != nil {
return nil, nil, err
}
return tx.tx.Driver, tx.txrrw, nil
case txModeAll:
// In file-mode, this function is called each time a new file is executed. Since we wrap all files into one
// huge transaction, if there already is an opened one, use that.
if tx.tx == nil {
var err error
tx.tx, err = tx.c.Tx(ctx, nil)
if err != nil {
return nil, nil, err
}
if tx.txrrw, err = entRevisions(ctx, tx.tx.Client, tx.schema); err != nil {
return nil, nil, err
}
}
return tx.tx.Driver, tx.txrrw, nil
default:
return nil, nil, fmt.Errorf("unknown tx-mode %q", mode)
}
}
// mayRollback may roll back a transaction depending on the given transaction mode.
func (tx *tx) mayRollback(err error) error {
if tx.tx != nil && err != nil {
if err2 := tx.tx.Rollback(); err2 != nil {
err = fmt.Errorf("%v: %w", err2, err)
}
}
return err
}
// mayCommit may commit a transaction depending on the given transaction mode.
func (tx *tx) mayCommit() error {
// Only commit if each file is wrapped in a transaction.
if tx.tx != nil && !tx.dryRun && tx.mode == txModeFile {
return tx.commit()
}
return nil
}
// commit the transaction, if one is active.
func (tx *tx) commit() error {
if tx.tx == nil {
return nil
}
defer func() { tx.tx, tx.txrrw = nil, nil }()
return tx.tx.Commit()
}
func (tx *tx) modeFor(f migrate.File) (string, error) {
l, ok := f.(*migrate.LocalFile)
if !ok {
return tx.mode, nil
}
switch m, err := txmodeFor(l); {
case err != nil:
return "", err
case m == "", m == tx.mode:
return tx.mode, nil
default: // m == txModeNone, m == txModeFile
if tx.mode == txModeAll {
return "", fmt.Errorf("cannot set txmode directive to %q in %q when txmode %q is set globally", m, l.Name(), txModeAll)
}
return m, nil
}
}
// txmodeFor returns the transaction mode for the given file.
func txmodeFor(f *migrate.LocalFile) (string, error) {
switch ds := f.Directive(txModeDirective); {
case len(ds) == 0:
return "", nil
case len(ds) > 1:
return "", fmt.Errorf("multiple txmode values found in file %q: %q", f.Name(), ds)
case ds[0] == txModeAll:
return "", fmt.Errorf("txmode %q is not allowed in file directive %q. Use %q instead", txModeAll, f.Name(), txModeFile)
case ds[0] == txModeNone, ds[0] == txModeFile:
return ds[0], nil
default:
return "", fmt.Errorf("unknown txmode %q found in file directive %q", ds[0], f.Name())
}
}
func operatorVersion() string {
v, _ := parseV(version)
return "Atlas CLI " + v
}
// dirFormatBC ensures the soon-to-be deprecated --dir-format flag gets set on all migration directory URLs.
func dirFormatBC(flag string, urls ...*string) error {
for _, s := range urls {
u, err := url.Parse(*s)
if err != nil {
return err
}
if !u.Query().Has("format") && flag != "" {
q := u.Query()
q.Set("format", flag)
u.RawQuery = q.Encode()
*s = u.String()
}
}
return nil
}
func checkDir(cmd *cobra.Command, url string, create bool) error {
d, err := cmdmigrate.Dir(cmd.Context(), url, create)
if err != nil {
return err
}
if err = migrate.Validate(d); err != nil {
printChecksumError(cmd, err)
return err
}
return nil
}
func printChecksumError(cmd *cobra.Command, err error) {
cmd.SilenceUsage = true
out := cmd.OutOrStderr()
fmt.Fprintln(out, "You have a checksum error in your migration directory.")
if csErr := (&migrate.ChecksumError{}); errors.As(err, &csErr) {
fmt.Fprintf(out, "\n\tL%d: %s was %s\n\n", csErr.Line, csErr.File, csErr.Reason)
}
fmt.Fprintf(
out,
"Please check your migration files and run %v to re-hash the contents\n\n",
cmdlog.ColorCyan("'atlas migrate hash'"),
)
}
// selectScheme validates the scheme of the provided to urls and returns the selected
// url scheme. Currently, all URLs must be of the same scheme, and only multiple
// "file://" URLs are allowed.
func selectScheme(urls []string) (string, error) {
var scheme string
if len(urls) == 0 {
return "", errors.New("at least one url is required")
}
for _, u := range urls {
parts := strings.SplitN(u, "://", 2)
switch current := parts[0]; {
case len(parts) == 1:
ex := filepath.Ext(u)
switch f, err := os.Stat(u); {
case err != nil:
case f.IsDir(), ex == cmdext.FileTypeSQL, ex == cmdext.FileTypeHCL:
return "", fmt.Errorf("missing scheme. Did you mean file://%s?", u)
}
return "", errors.New("missing scheme. See: https://atlasgo.io/url")
case scheme == "":
scheme = current
case scheme != current:
return "", fmt.Errorf("got mixed --to url schemes: %q and %q, the desired state must be provided from a single kind of source", scheme, current)
case current != cmdext.SchemaTypeFile:
return "", fmt.Errorf("got multiple --to urls of scheme %q, only multiple 'file://' urls are supported", current)
}
}
return scheme, nil
}
func migrateFlagsFromConfig(cmd *cobra.Command) error {
env, err := selectEnv(cmd)
if err != nil {
return err
}
return setMigrateEnvFlags(cmd, env)
}
func setMigrateEnvFlags(cmd *cobra.Command, env *Env) error {
if err := maySetFlag(cmd, flagURL, env.URL); err != nil {
return err
}
if err := maySetFlag(cmd, flagDevURL, env.DevURL); err != nil {
return err
}
if err := maySetFlag(cmd, flagDirURL, env.Migration.Dir); err != nil {
return err
}
if err := maySetFlag(cmd, flagDirFormat, env.Migration.Format); err != nil {
return err
}
if err := maySetFlag(cmd, flagBaseline, env.Migration.Baseline); err != nil {
return err
}
if err := maySetFlag(cmd, flagRevisionSchema, env.Migration.RevisionsSchema); err != nil {
return err
}
switch cmd.Name() {
case "apply":
if err := maySetFlag(cmd, flagFormat, env.Format.Migrate.Apply); err != nil {
return err
}
if err := maySetFlag(cmd, flagLockTimeout, env.Migration.LockTimeout); err != nil {
return err
}
if err := maySetFlag(cmd, flagExecOrder, strings.ReplaceAll(strings.ToLower(env.Migration.ExecOrder), "_", "-")); err != nil {
return err
}
case "down":
if err := maySetFlag(cmd, flagFormat, env.Format.Migrate.Down); err != nil {
return err
}
if err := maySetFlag(cmd, flagLockTimeout, env.Migration.LockTimeout); err != nil {
return err
}
case "diff", "checkpoint":
if err := maySetFlag(cmd, flagLockTimeout, env.Migration.LockTimeout); err != nil {
return err
}
if err := maySetFlag(cmd, flagFormat, env.Format.Migrate.Diff); err != nil {
return err
}
case "lint":
if err := maySetFlag(cmd, flagFormat, env.Format.Migrate.Lint); err != nil {
return err
}
if err := maySetFlag(cmd, flagFormat, env.Lint.Format); err != nil {
return err
}
if err := maySetFlag(cmd, flagLatest, strconv.Itoa(env.Lint.Latest)); err != nil {
return err
}
if err := maySetFlag(cmd, flagGitDir, env.Lint.Git.Dir); err != nil {
return err
}
if err := maySetFlag(cmd, flagGitBase, env.Lint.Git.Base); err != nil {
return err
}
case "status":
if err := maySetFlag(cmd, flagFormat, env.Format.Migrate.Status); err != nil {
return err
}
}
// Transform "src" to a URL.
srcs, err := env.Sources()
if err != nil {
return err
}
for i, s := range srcs {
if isURL(s) {
continue
}
if s, err = filepath.Abs(s); err != nil {
return fmt.Errorf("finding abs path to source: %q: %w", s, err)
}
srcs[i] = "file://" + s
}
if err := maySetFlag(cmd, flagTo, strings.Join(srcs, ",")); err != nil {
return err
}
if err := maySetFlag(cmd, flagSchema, strings.Join(env.Schemas, ",")); err != nil {
return err
}
return nil
}
// isURL returns true if the given string
// is an Atlas URL with a scheme.
func isURL(s string) bool {
u, err := url.Parse(s)
return err == nil && u.Scheme != ""
}
// cmdEnvsRun executes a given command on each of the configured environment.
func cmdEnvsRun(
envs []*Env,
setFlags func(*cobra.Command, *Env) error,
cmd *cobra.Command,
runCmd func(*Env) error,
) error {
var (
w bytes.Buffer
out = cmd.OutOrStdout()
reset = resetFromEnv(cmd)
)
cmd.SetOut(io.MultiWriter(out, &w))
defer cmd.SetOut(out)
for i, e := range envs {
if err := setFlags(cmd, e); err != nil {
return err
}
if err := runCmd(e); err != nil {
return err
}
b := bytes.TrimLeft(w.Bytes(), " \t\r")
// In case a custom logging was configured, ensure there is
// a newline separator between the different environments.
if cmd.Flags().Changed(flagFormat) && bytes.LastIndexByte(b, '\n') != len(b)-1 && i != len(envs)-1 {
cmd.Println()
}
reset()
w.Reset()
}
return nil
}
type editDir struct{ *migrate.LocalDir }
// WriteFile implements the migrate.Dir.WriteFile method.
func (d *editDir) WriteFile(name string, b []byte) (err error) {
if name != migrate.HashFileName {
if b, err = edit(name, b); err != nil {
return err
}
}
return d.LocalDir.WriteFile(name, b)
}
// edit allows editing the file content using editor.
func edit(name string, src []byte) ([]byte, error) {
p := filepath.Join(os.TempDir(), name)
if err := os.WriteFile(p, src, 0644); err != nil {
return nil, fmt.Errorf("write source content to temp file: %w", err)
}
defer os.Remove(p)
editor := "vi"
if e := os.Getenv("EDITOR"); e != "" {
editor = e
}
cmd := exec.Command("sh", "-c", editor+" "+p)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("exec edit: %w", err)
}
b, err := os.ReadFile(p)
if err != nil {
return nil, fmt.Errorf("read edited temp file: %w", err)
}
return b, nil
}
type (
// dryRunDriver wraps a migrate.Driver without executing any SQL statements.
dryRunDriver struct{ migrate.Driver }
// dryRunRevisions wraps a migrate.RevisionReadWriter without executing any SQL statements.
dryRunRevisions struct{ migrate.RevisionReadWriter }
)
// ExecContext overrides the wrapped schema.ExecQuerier to not execute any SQL.
func (dryRunDriver) ExecContext(context.Context, string, ...any) (sql.Result, error) {
return nil, nil
}
// Lock implements the schema.Locker interface.
func (dryRunDriver) Lock(context.Context, string, time.Duration) (schema.UnlockFunc, error) {
// We dry-run, we don't execute anything. Locking is not required.
return func() error { return nil }, nil
}
// CheckClean implements the migrate.CleanChecker interface.
func (dryRunDriver) CheckClean(context.Context, *migrate.TableIdent) error {
return nil
}
// Snapshot implements the migrate.Snapshoter interface.
func (dryRunDriver) Snapshot(context.Context) (migrate.RestoreFunc, error) {
// We dry-run, we don't execute anything. Snapshotting not required.
return func(context.Context) error { return nil }, nil
}
// WriteRevision overrides the wrapped migrate.RevisionReadWriter to not saved any changes to revisions.
func (dryRunRevisions) WriteRevision(context.Context, *migrate.Revision) error {
return nil
}
================================================
FILE: cmd/atlas/internal/cmdapi/migrate_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package cmdapi
import (
"errors"
"fmt"
"net/url"
"strconv"
"ariga.io/atlas/cmd/atlas/internal/cmdlog"
cmdmigrate "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/sql/migrate"
"github.com/spf13/cobra"
)
// migrateApplyRun represents the 'atlas migrate apply' subcommand.
func migrateApplyRun(cmd *cobra.Command, args []string, flags migrateApplyFlags, env *Env, mr *MigrateReport) (err error) {
var (
count int
ctx = cmd.Context()
)
if len(args) > 0 {
if count, err = strconv.Atoi(args[0]); err != nil {
if nerr := (&strconv.NumError{}); errors.As(err, &nerr) && nerr.Err != nil {
err = nerr.Err
}
return fmt.Errorf("invalid amount argument %q (%w). Omit the argument or pass a valid integer instead", args[0], err)
}
if count < 1 {
return fmt.Errorf("cannot apply '%d' migration files", count)
}
}
dirURL, err := url.Parse(flags.dirURL)
if err != nil {
return fmt.Errorf("parse dir-url: %w", err)
}
// Open and validate the migration directory.
dir, err := cmdmigrate.DirURL(ctx, dirURL, false)
if err != nil {
return err
}
if err := migrate.Validate(dir); err != nil {
printChecksumError(cmd, err)
return err
}
// Open a client to the database.
if flags.url == "" {
return errors.New(`required flag "url" not set`)
}
client, err := env.openClient(ctx, flags.url)
if err != nil {
return err
}
defer client.Close()
// Prevent usage printing after input validation.
cmd.SilenceUsage = true
// Acquire a lock.
unlock, err := client.Driver.Lock(ctx, applyLockValue, flags.lockTimeout)
if err != nil {
return fmt.Errorf("acquiring database lock: %w", err)
}
// If unlocking fails notify the user about it.
defer func() { cobra.CheckErr(unlock()) }()
if err := checkRevisionSchemaClarity(cmd, client, flags.revisionSchema); err != nil {
return err
}
var rrw migrate.RevisionReadWriter
if rrw, err = entRevisions(ctx, client, flags.revisionSchema); err != nil {
return err
}
mrrw, ok := rrw.(cmdmigrate.RevisionReadWriter)
if !ok {
return fmt.Errorf("unexpected revision read-writer type: %T", rrw)
}
if err := mrrw.Migrate(ctx); err != nil {
return err
}
// Setup reporting info.
report := cmdlog.NewMigrateApply(ctx, client, dirURL)
mr.Init(client, report, mrrw)
// If cloud reporting is enabled, and we cannot obtain the current
// target identifier, abort and report it to the user.
if err := mr.RecordTargetID(cmd.Context()); err != nil {
return err
}
// Determine pending files.
opts, err := flags.migrateOptions()
if err != nil {
return err
}
opts = append(opts, migrate.WithOperatorVersion(operatorVersion()), migrate.WithLogger(report))
ex, err := migrate.NewExecutor(client.Driver, dir, rrw, opts...)
if err != nil {
return err
}
pending, err := ex.Pending(ctx)
if err != nil && !errors.Is(err, migrate.ErrNoPendingFiles) {
mr.RecordPlanError(cmd, flags, err.Error())
return err
}
noPending := errors.Is(err, migrate.ErrNoPendingFiles)
// Get the pending files before obtaining applied revisions,
// as the Executor may write a baseline revision in the table.
applied, err := rrw.ReadRevisions(ctx)
if err != nil {
return err
}
if noPending {
migrate.LogNoPendingFiles(report, applied)
return mr.Done(cmd, flags)
}
if l := len(pending); count == 0 || count >= l {
// Cannot apply more than len(pending) migration files.
count = l
}
pending = pending[:count]
migrate.LogIntro(report, applied, pending)
var (
mux = tx{
dryRun: flags.dryRun,
mode: flags.txMode,
schema: flags.revisionSchema,
c: client,
rrw: rrw,
}
drv migrate.Driver
)
for _, f := range pending {
if drv, rrw, err = mux.driverFor(ctx, f); err != nil {
break
}
if ex, err = migrate.NewExecutor(drv, dir, rrw, opts...); err != nil {
return fmt.Errorf("unexpected executor creation error: %w", err)
}
if err = mux.mayRollback(ex.Execute(ctx, f)); err != nil {
break
}
if err = mux.mayCommit(); err != nil {
break
}
}
if err == nil {
if err = mux.commit(); err == nil {
report.Log(migrate.LogDone{})
}
}
if err != nil {
report.Error = err.Error()
}
return errors.Join(err, mr.Done(cmd, flags))
}
================================================
FILE: cmd/atlas/internal/cmdapi/migrate_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"io"
"net/url"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
"ariga.io/atlas/cmd/atlas/internal/cmdlog"
migrate2 "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
"ariga.io/atlas/sql/sqlite"
_ "ariga.io/atlas/sql/sqlite"
_ "ariga.io/atlas/sql/sqlite/sqlitecheck"
"github.com/fatih/color"
"github.com/google/uuid"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
)
func TestMigrate(t *testing.T) {
_, err := runCmd(migrateCmd())
require.NoError(t, err)
}
func TestMigrate_Import(t *testing.T) {
for _, tool := range []string{"dbmate", "flyway", "golang-migrate", "goose", "liquibase"} {
p := t.TempDir()
t.Run(tool, func(t *testing.T) { // remove this once --dir-format is removed. Test is kept to ensure BC.
path := filepath.FromSlash("testdata/import/" + tool)
out, err := runCmd(
migrateImportCmd(),
"--from", "file://"+path,
"--to", "file://"+p,
"--dir-format", tool,
)
require.NoError(t, err)
require.Zero(t, out)
path += "_gold"
ex, err := os.ReadDir(path)
require.NoError(t, err)
ac, err := os.ReadDir(p)
require.NoError(t, err)
require.Equal(t, len(ex)+1, len(ac)) // sum file
for i := range ex {
e, err := os.ReadFile(filepath.Join(path, ex[i].Name()))
require.NoError(t, err)
a, err := os.ReadFile(filepath.Join(p, ex[i].Name()))
require.NoError(t, err)
require.Equal(t, string(e), string(a))
}
})
p = t.TempDir()
t.Run(tool, func(t *testing.T) {
path := filepath.FromSlash("testdata/import/" + tool)
out, err := runCmd(
migrateImportCmd(),
"--from", fmt.Sprintf("file://%s?format=%s", path, tool),
"--to", "file://"+p,
)
require.NoError(t, err)
require.Zero(t, out)
path += "_gold"
ex, err := os.ReadDir(path)
require.NoError(t, err)
ac, err := os.ReadDir(p)
require.NoError(t, err)
require.Equal(t, len(ex)+1, len(ac)) // sum file
for i := range ex {
e, err := os.ReadFile(filepath.Join(path, ex[i].Name()))
require.NoError(t, err)
a, err := os.ReadFile(filepath.Join(p, ex[i].Name()))
require.NoError(t, err)
require.Equal(t, string(e), string(a))
}
})
}
}
func TestMigrate_Apply(t *testing.T) {
var (
p = t.TempDir()
ctx = context.Background()
)
// Disable text coloring in testing
// to assert on string matching.
color.NoColor = true
// Fails on empty directory.
s, err := runCmd(
migrateApplyCmd(),
"--dir", "file://"+p,
"-u", openSQLite(t, ""),
)
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", s)
// Fails on directory without sum file.
require.NoError(t, os.Rename(
filepath.FromSlash("testdata/sqlite/atlas.sum"),
filepath.FromSlash("testdata/sqlite/atlas.sum.bak"),
))
t.Cleanup(func() {
os.Rename(filepath.FromSlash("testdata/sqlite/atlas.sum.bak"), filepath.FromSlash("testdata/sqlite/atlas.sum"))
})
_, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite",
"--url", openSQLite(t, ""),
)
require.ErrorIs(t, err, migrate.ErrChecksumNotFound)
require.NoError(t, os.Rename(
filepath.FromSlash("testdata/sqlite/atlas.sum.bak"),
filepath.FromSlash("testdata/sqlite/atlas.sum"),
))
// A lock will prevent execution.
sqlclient.Register(
"sqlitelockapply",
sqlclient.OpenerFunc(func(ctx context.Context, u *url.URL) (*sqlclient.Client, error) {
client, err := sqlclient.Open(ctx, strings.Replace(u.String(), u.Scheme, "sqlite", 1))
if err != nil {
return nil, err
}
client.Driver = &sqliteLockerDriver{client.Driver}
return client, nil
}),
sqlclient.RegisterDriverOpener(func(db schema.ExecQuerier) (migrate.Driver, error) {
drv, err := sqlite.Open(db)
if err != nil {
return nil, err
}
return &sqliteLockerDriver{drv}, nil
}),
)
f, err := os.Create(filepath.Join(p, "test.db"))
require.NoError(t, err)
require.NoError(t, f.Close())
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite",
"--url", fmt.Sprintf("sqlitelockapply://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
)
require.ErrorIs(t, err, errLock)
require.True(t, strings.HasPrefix(s, "Error: acquiring database lock: "+errLock.Error()))
// Apply zero throws error.
for _, n := range []string{"-1", "0"} {
_, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"--", n,
)
require.EqualError(t, err, fmt.Sprintf("cannot apply '%s' migration files", n))
}
// Will work and print stuff to the console.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"1",
)
require.NoError(t, err)
require.Contains(t, s, "20220318104614") // log to version
require.Contains(t, s, "CREATE TABLE tbl (`col` int NOT NULL);") // logs statement
require.NotContains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // does not execute second file
require.Contains(t, s, "1 migration") // logs amount of migrations
require.Contains(t, s, "1 sql statement")
// Transactions will be wrapped per file. If the second file has an error, first still is applied.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.Error(t, err)
require.Contains(t, s, "20220318104614") // log to version
require.Contains(t, s, "CREATE TABLE tbl (`col` int NOT NULL);") // logs statement
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // does execute first stmt first second file
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_3` bigint;") // does execute second stmt first second file
require.NotContains(t, s, "ALTER TABLE `tbl` ADD `col_4` bigint;") // but not third
require.Contains(t, s, "-- 1 migration ok, 1 with errors") // logs amount of migrations
require.Contains(t, s, "-- 2 sql statements ok, 1 with errors") // logs amount of statement
require.Contains(t, s, "near \"asdasd\": syntax error") // logs error summary
c, err := sqlclient.Open(ctx, fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c.Close())
})
sch, err := c.InspectSchema(ctx, "", nil)
tbl, ok := sch.Table("tbl")
require.True(t, ok)
_, ok = tbl.Column("col_2")
require.False(t, ok)
_, ok = tbl.Column("col_3")
require.False(t, ok)
rrw, err := migrate2.NewEntRevisions(ctx, c)
require.NoError(t, err)
revs, err := rrw.ReadRevisions(ctx)
require.NoError(t, err)
require.Len(t, revs, 1)
// Running again will pick up the failed statement and try it again.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.Error(t, err)
require.Contains(t, s, "20220318104614") // currently applied version
require.Contains(t, s, "20220318104615") // retry second (partially applied)
require.NotContains(t, s, "CREATE TABLE tbl (`col` int NOT NULL);") // will not attempt stmts from first file
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // picks up first statement
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_3` bigint;") // does execute second stmt first second file
require.NotContains(t, s, "ALTER TABLE `tbl` ADD `col_4` bigint;") // but not third
require.Contains(t, s, "-- 1 migration with errors") // logs amount of migrations
require.Contains(t, s, "-- 1 sql statement ok, 1 with errors") // logs amount of statement
require.Contains(t, s, "near \"asdasd\": syntax error") // logs error summary
// Editing an applied line will raise error.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
"--tx-mode", "none",
)
t.Cleanup(func() {
_ = os.RemoveAll("testdata/sqlite3")
})
require.NoError(t, exec.Command("cp", "-r", "testdata/sqlite2", "testdata/sqlite3").Run())
sed(t, "s/col_2/col_5/g", "testdata/sqlite3/20220318104615_second.sql")
_, err = runCmd(migrateHashCmd(), "--dir", "file://testdata/sqlite3")
require.NoError(t, err)
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.ErrorAs(t, err, &migrate.HistoryChangedError{})
// Fixing the migration file will finish without errors.
sed(t, "s/col_5/col_2/g", "testdata/sqlite3/20220318104615_second.sql")
sed(t, "s/asdasd //g", "testdata/sqlite3/20220318104615_second.sql")
_, err = runCmd(migrateHashCmd(), "--dir", "file://testdata/sqlite3")
require.NoError(t, err)
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.NoError(t, err)
require.Contains(t, s, "20220318104615") // retry second (partially applied)
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_3` bigint;") // does execute second stmt first second file
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_4` bigint;") // does execute second stmt first second file
require.Contains(t, s, "1 migrations") // logs amount of migrations
require.Contains(t, s, "2") // logs amount of statement
require.NotContains(t, s, "Error: Execution had errors:") // logs error summary
require.NotContains(t, s, "near \"asdasd\": syntax error") // logs error summary
// Running again will report database being in clean state.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", s)
// Dry run will print the statements in second migration file without executing them.
// No changes to the revisions will be done.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"--dry-run",
"1",
)
require.NoError(t, err)
require.Contains(t, s, "20220318104615") // log to version
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // logs statement
c1, err := sqlclient.Open(ctx, fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c1.Close())
})
sch, err = c1.InspectSchema(ctx, "", nil)
tbl, ok = sch.Table("tbl")
require.True(t, ok)
_, ok = tbl.Column("col_2")
require.False(t, ok)
rrw, err = migrate2.NewEntRevisions(ctx, c1)
require.NoError(t, err)
revs, err = rrw.ReadRevisions(ctx)
require.NoError(t, err)
require.Len(t, revs, 1)
// Prerequisites for testing missing migration behavior.
c1, err = sqlclient.Open(ctx, fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c1.Close())
})
require.NoError(t, os.Rename(
"testdata/sqlite3/20220318104615_second.sql",
"testdata/sqlite3/20220318104616_second.sql",
))
_, err = runCmd(migrateHashCmd(), "--dir", "file://testdata/sqlite3")
require.NoError(t, err)
rrw, err = migrate2.NewEntRevisions(ctx, c1)
require.NoError(t, err)
require.NoError(t, rrw.Migrate(ctx))
// No changes if the last revision has a greater version than the last migration.
require.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: "zzz"}))
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")),
)
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", s)
// If the revision is before the last but after the first migration, only the last one is pending.
_, err = c1.ExecContext(ctx, "DROP table `atlas_schema_revisions`")
require.NoError(t, err)
s, err = runCmd(
migrateApplyCmd(), "1",
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")),
)
require.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: "20220318104615"}))
require.NoError(t, err)
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")),
)
require.NoError(t, err)
require.NotContains(t, s, "20220318104614") // log to version
require.Contains(t, s, "20220318104616") // log to version
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // logs statement
// If the revision is before every migration file, every file is pending.
_, err = c1.ExecContext(ctx, "DROP table `atlas_schema_revisions`; DROP table `tbl`;")
require.NoError(t, err)
require.NoError(t, rrw.Migrate(ctx))
require.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: "1"}))
require.NoError(t, err)
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")),
)
require.NoError(t, err)
require.Contains(t, s, "20220318104614") // log to version
require.Contains(t, s, "20220318104616") // log to version
require.Contains(t, s, "CREATE TABLE tbl (`col` int NOT NULL);") // logs statement
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // logs statement
// If the revision is partially applied, error out.
require.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: "z", Description: "z", Total: 1}))
require.NoError(t, err)
_, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")),
)
require.EqualError(t, err, migrate.MissingMigrationError{Version: "z", Description: "z"}.Error())
}
func TestMigrate_ApplyMultiEnv(t *testing.T) {
t.Run("FromVars", func(t *testing.T) {
p := t.TempDir()
h := `
variable "urls" {
type = list(string)
}
env "local" {
for_each = toset(var.urls)
url = each.value
dev = "sqlite://ci?mode=memory&cache=shared&_fk=1"
migration {
dir = "file://testdata/sqlite"
}
}
`
path := filepath.Join(p, "atlas.hcl")
err := os.WriteFile(path, []byte(h), 0600)
require.NoError(t, err)
cmd := migrateCmd()
cmd.AddCommand(migrateApplyCmd())
s, err := runCmd(
cmd, "apply",
"-c", "file://"+path,
"--env", "local",
"--var", fmt.Sprintf("urls=sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test1.db")),
"--var", fmt.Sprintf("urls=sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.NoError(t, err)
require.Equal(t, 2, strings.Count(s, "Migrating to version 20220318104615 (2 migrations in total)"), "execution per environment")
_, err = os.Stat(filepath.Join(p, "test1.db"))
require.NoError(t, err)
_, err = os.Stat(filepath.Join(p, "test2.db"))
require.NoError(t, err)
})
t.Run("FromDataSrc", func(t *testing.T) {
var (
h = `
variable "url" {
type = string
}
locals {
string = "%test"
bool = true
int = 1
}
data "sql" "tenants" {
url = var.url
query = <")
_, err = db.Exec("DELETE FROM `tenants`")
require.NoError(t, err)
s, err = runCmd(
cmd, "apply",
"-c", "file://"+path,
"--env", "local",
"--var", fmt.Sprintf("url=sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "tenants.db")),
// Inject fake variable to enforce re-evaluation of the data source (skip cache).
"--var", fmt.Sprintf("cache=%s", uuid.NewString()),
)
// Empty list is expanded to zero blocks.
require.EqualError(t, err, `env "local" not defined in config file`)
})
t.Run("TemplateDir", func(t *testing.T) {
var (
h = `
variable "path" {
type = string
}
data "template_dir" "migrations" {
path = var.path
vars = {
Env = atlas.env
}
}
env "dev" {
url = "sqlite://${atlas.env}?mode=memory&_fk=1"
migration {
dir = data.template_dir.migrations.url
}
}
env "prod" {
url = "sqlite://${atlas.env}?mode=memory&_fk=1"
migration {
dir = data.template_dir.migrations.url
}
}
`
p = t.TempDir()
path = filepath.Join(p, "atlas.hcl")
)
err := os.WriteFile(path, []byte(h), 0600)
require.NoError(t, err)
for _, e := range []string{"dev", "prod"} {
cmd := migrateCmd()
cmd.AddCommand(migrateApplyCmd())
s, err := runCmd(
cmd, "apply",
"-c", "file://"+path,
"--env", e,
"--var", "path=testdata/templatedir",
)
require.NoError(t, err)
require.Contains(t, s, "Migrating to version 2 (2 migrations in total):")
require.Contains(t, s, fmt.Sprintf("create table %s1 (c text);", e))
require.Contains(t, s, fmt.Sprintf("create table %s2 (c text);", e))
require.Contains(t, s, fmt.Sprintf("create table users_%s2 (c text);", e))
}
})
}
func TestMigrate_ApplyTxMode(t *testing.T) {
for _, mode := range []string{"none", "file", "all"} {
t.Run(mode, func(t *testing.T) {
p := t.TempDir()
// Apply the first 2 migrations.
s, err := runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlitetx",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"--tx-mode", mode,
"2",
)
require.NoError(t, err)
require.NotEmpty(t, s)
db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")))
require.NoError(t, err)
var n int
require.NoError(t, db.QueryRow("SELECT COUNT(*) FROM `friendships`").Scan(&n))
require.Equal(t, 2, n)
// Apply the rest.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlitetx",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"--tx-mode", mode,
)
require.NoError(t, err)
require.NoError(t, db.QueryRow("SELECT COUNT(*) FROM `friendships`").Scan(&n))
require.Equal(t, 2, n)
// For transactions check that the foreign keys are checked before the transaction is committed.
if mode != "none" {
// Apply the first 2 migrations for the faulty one.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlitetx2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test_2.db")),
"--tx-mode", mode,
"2",
)
require.NoError(t, err)
require.NotEmpty(t, s)
db, err = sql.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared&_fk=1", filepath.Join(p, "test_2.db")))
require.NoError(t, err)
require.NoError(t, db.QueryRow("SELECT COUNT(*) FROM `friendships`").Scan(&n))
require.Equal(t, 2, n)
// Add an existing constraint.
c, err := sqlclient.Open(context.Background(), fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test_2.db")))
require.NoError(t, err)
_, err = c.ExecContext(context.Background(), "PRAGMA foreign_keys = off; INSERT INTO `friendships` (`user_id`, `friend_id`) VALUES (3,3);PRAGMA foreign_keys = on;")
require.NoError(t, err)
require.NoError(t, db.QueryRow("SELECT COUNT(*) FROM `friendships`").Scan(&n))
require.Equal(t, 3, n)
// Apply the rest, expect it to fail due to constraint error, but only the new one is reported.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlitetx2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test_2.db")),
"--tx-mode", mode,
)
require.EqualError(t, err, "sql/sqlite: foreign key mismatch: [{tbl:friendships ref:users row:4 index:1}]")
require.NoError(t, db.QueryRow("SELECT COUNT(*) FROM `friendships`").Scan(&n))
require.Equal(t, 3, n) // was rolled back
}
})
}
}
func TestMigrate_ApplyTxModeDirective(t *testing.T) {
for _, mode := range []string{txModeNone, txModeFile} {
u := openSQLite(t, "")
_, err := runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlitetx3",
"--url", u,
"--tx-mode", mode,
)
require.EqualError(t, err, `sql/migrate: executing statement "INSERT INTO t1 VALUES (1), (1);" from version "20220925094021": UNIQUE constraint failed: t1.a`)
db, err := sql.Open("sqlite3", strings.TrimPrefix(u, "sqlite://"))
require.NoError(t, err)
var n int
require.NoError(t, db.QueryRow("SELECT COUNT(*) FROM sqlite_master WHERE name IN ('atlas_schema_revisions', 'users', 't1')").Scan(&n))
require.Equal(t, 3, n)
require.NoError(t, db.Close())
}
_, err := runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlitetx3",
"--url", "sqlite://txmode?mode=memory&_fk=1",
"--tx-mode", txModeAll,
)
require.EqualError(t, err, `cannot set txmode directive to "none" in "20220925094021_second.sql" when txmode "all" is set globally`)
s, err := runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlitetx4",
"--url", "sqlite://txmode?mode=memory&_fk=1",
"--tx-mode", txModeAll,
"--log", "{{ .Error }}",
)
require.EqualError(t, err, `unknown txmode "unknown" found in file directive "20220925094021_second.sql"`)
// Errors should be attached to the report.
require.Equal(t, s, `unknown txmode "unknown" found in file directive "20220925094021_second.sql"`)
}
func TestMigrate_ApplyExecOrder(t *testing.T) {
p := t.TempDir()
db := fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db"))
require.NoError(t, os.Mkdir(filepath.Join(p, "migrations"), 0700))
dir, err := migrate.NewLocalDir(filepath.Join(p, "migrations"))
require.NoError(t, err)
write := func(n, b string) {
require.NoError(t, dir.WriteFile(n, []byte(b)))
hash, err := dir.Checksum()
require.NoError(t, err)
require.NoError(t, migrate.WriteSumFile(dir, hash))
}
write("1.sql", "create table t1(c int);")
write("3.sql", "create table t3(c int);")
// First run.
s, err := runCmd(
migrateApplyCmd(),
"--dir", "file://"+dir.Path(),
"--url", db,
"--format", "{{ len .Applied }}",
)
require.NoError(t, err)
require.Equal(t, "2", s)
// File was added out of order.
write("2.sql", "create table t2(c int);")
_, err = runCmd(
migrateApplyCmd(),
"--dir", "file://"+dir.Path(),
"--url", db,
)
require.EqualError(t, err, "migration file 2.sql was added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error")
// The "linear" option is the default execution order.
_, err = runCmd(
migrateApplyCmd(),
"--dir", "file://"+dir.Path(),
"--url", db,
"--exec-order", "linear",
)
require.EqualError(t, err, "migration file 2.sql was added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error")
// Keep linear order and skip files that were added out of order.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://"+dir.Path(),
"--url", db,
"--exec-order", "linear-skip",
)
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", s)
// Allow non-linear order.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://"+dir.Path(),
"--url", db,
"--exec-order", "non-linear",
"--format", "{{ range .Applied }}{{ .Version }}{{ end }}",
)
require.NoError(t, err)
require.Equal(t, "2", s)
write("2.5.sql", "create table t25(c int);")
write("4.sql", "create table t4(c int);")
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://"+dir.Path(),
"--url", db,
"--exec-order", "non-linear",
"--format", "{{ range .Applied }}{{ println .Version }}{{ end }}",
)
require.NoError(t, err)
require.Equal(t, "2.5\n4\n", s)
// There are no pending migrations, in all execution orders.
for _, o := range []string{"linear", "linear-skip", "non-linear"} {
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://"+dir.Path(),
"--url", db,
"--exec-order", o,
)
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", s)
}
}
func TestMigrate_ApplyBaseline(t *testing.T) {
t.Run("FromFlags", func(t *testing.T) {
p := t.TempDir()
// Run migration with baseline should store this revision in the database.
s, err := runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/baseline1",
"--baseline", "1",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test1.db")),
)
require.NoError(t, err)
require.Contains(t, s, "No migration files to execute")
// Next run without baseline should run the migration from the baseline.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/baseline1",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test1.db")),
)
require.NoError(t, err)
require.Contains(t, s, "No migration files to execute")
// Multiple migration files with baseline.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/baseline2",
"--baseline", "1",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.NoError(t, err)
require.Contains(t, s, "Migrating to version 20220318104615 from 1 (2 migrations in total)")
// Run all migration files and skip baseline.
s, err = runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/baseline2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")),
)
require.NoError(t, err)
require.Contains(t, s, "Migrating to version 20220318104615 (3 migrations in total)")
})
t.Run("FromConfig", func(t *testing.T) {
const h = `
env "local" {
migration {
baseline = "1"
}
}`
p := t.TempDir()
path := filepath.Join(p, "atlas.hcl")
err := os.WriteFile(path, []byte(h), 0600)
require.NoError(t, err)
cmd := migrateCmd()
cmd.AddCommand(migrateApplyCmd())
s, err := runCmd(
cmd, "apply",
"-c", "file://"+path,
"--env", "local",
"--dir", "file://testdata/baseline1",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test1.db")),
)
require.NoError(t, err)
require.Contains(t, s, "No migration files to execute")
cmd = migrateCmd()
cmd.AddCommand(migrateApplyCmd())
s, err = runCmd(
cmd, "apply",
"-c", "file://"+path,
"--env", "local",
"--dir", "file://testdata/baseline2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.NoError(t, err)
require.Contains(t, s, "Migrating to version 20220318104615 from 1 (2 migrations in total)")
})
}
func TestMigrate_Diff(t *testing.T) {
p := t.TempDir()
to := hclURL(t)
// Will create migration directory if not existing.
_, err := runCmd(
migrateDiffCmd(),
"name",
"--dir", "file://"+filepath.Join(p, "migrations"),
"--dev-url", openSQLite(t, ""),
"--to", to,
)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, "migrations", fmt.Sprintf("%s_name.sql", time.Now().UTC().Format("20060102150405"))))
// Expect no clean dev error.
p = t.TempDir()
s, err := runCmd(
migrateDiffCmd(),
"name",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, "create table t (c int);"),
"--to", to,
)
require.ErrorAs(t, err, new(*migrate.NotCleanError))
require.ErrorContains(t, err, "found table \"t\"")
// Works (on empty directory).
s, err = runCmd(
migrateDiffCmd(),
"name",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"--to", to,
)
require.NoError(t, err)
require.Zero(t, s)
require.FileExists(t, filepath.Join(p, fmt.Sprintf("%s_name.sql", time.Now().UTC().Format("20060102150405"))))
require.FileExists(t, filepath.Join(p, "atlas.sum"))
// A lock will prevent diffing.
sqlclient.Register("sqlitelockdiff", sqlclient.OpenerFunc(func(ctx context.Context, u *url.URL) (*sqlclient.Client, error) {
u.Scheme = "sqlite"
client, err := sqlclient.OpenURL(ctx, u)
if err != nil {
return nil, err
}
client.Driver = &sqliteLockerDriver{Driver: client.Driver}
return client, nil
}))
f, err := os.Create(filepath.Join(p, "test.db"))
require.NoError(t, err)
require.NoError(t, f.Close())
s, err = runCmd(
migrateDiffCmd(),
"name",
"--dir", "file://"+t.TempDir(),
"--dev-url", fmt.Sprintf("sqlitelockdiff://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"--to", to,
)
require.True(t, strings.HasPrefix(s, "Error: acquiring database lock: "+errLock.Error()))
require.ErrorIs(t, err, errLock)
t.Run("Edit", func(t *testing.T) {
p := t.TempDir()
t.Setenv("EDITOR", "echo '-- Comment' >>")
args := []string{
"--edit",
"--dir", "file://" + p,
"--dev-url", openSQLite(t, ""),
"--to", to,
}
_, err := runCmd(migrateDiffCmd(), args...)
files, err := os.ReadDir(p)
require.NoError(t, err)
require.Len(t, files, 2)
b, err := os.ReadFile(filepath.Join(p, files[0].Name()))
require.NoError(t, err)
require.Contains(t, string(b), "CREATE")
require.True(t, strings.HasSuffix(string(b), "-- Comment\n"))
require.Equal(t, "atlas.sum", files[1].Name())
// Second run will have no effect.
_, err = runCmd(migrateDiffCmd(), args...)
require.NoError(t, err)
files, err = os.ReadDir(p)
require.NoError(t, err)
require.Len(t, files, 2)
})
t.Run("Format", func(t *testing.T) {
for f, out := range map[string]string{
"{{sql .}}": "CREATE TABLE `t` (`c` int NULL);",
`{{- sql . " " -}}`: "CREATE TABLE `t` (\n `c` int NULL\n);",
"{{ sql . \"\t\" }}": "CREATE TABLE `t` (\n\t`c` int NULL\n);",
"{{sql $ \" \t \"}}": "CREATE TABLE `t` (\n \t `c` int NULL\n);",
} {
p := t.TempDir()
d, err := migrate.NewLocalDir(p)
require.NoError(t, err)
// Works with indentation.
s, err = runCmd(
migrateDiffCmd(),
"name",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"--to", openSQLite(t, "create table t (c int);"),
"--format", f,
)
require.NoError(t, err)
require.Zero(t, s)
files, err := d.Files()
require.NoError(t, err)
require.Len(t, files, 1)
require.Equal(t, "-- Create \"t\" table\n"+out+"\n", string(files[0].Bytes()))
}
// Invalid use of sql.
s, err = runCmd(
migrateDiffCmd(),
"name",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"--to", openSQLite(t, "create table t (c int);"),
"--format", `{{ if . }}{{ sql . " " }}{{ end }}`,
)
require.EqualError(t, err, `'sql' can only be used to indent statements. got: {{if .}}{{sql . " "}}{{end}}`)
// Valid template.
p := t.TempDir()
d, err := migrate.NewLocalDir(p)
require.NoError(t, err)
s, err = runCmd(
migrateDiffCmd(),
"name",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"--to", openSQLite(t, "create table t (c int);"),
"--format", `{{ range .Changes }}{{ .Cmd }}{{ end }}`,
)
require.NoError(t, err)
files, err := d.Files()
require.NoError(t, err)
require.Len(t, files, 1)
require.Equal(t, "CREATE TABLE `t` (`c` int NULL)", string(files[0].Bytes()))
})
t.Run("ProjectFile", func(t *testing.T) {
p := t.TempDir()
h := `
variable "schema" {
type = string
}
variable "dir" {
type = string
}
variable "destructive" {
type = bool
default = false
}
env "local" {
src = "file://${var.schema}"
dev = "sqlite://ci?mode=memory&_fk=1"
migration {
dir = "file://${var.dir}"
}
diff {
skip {
drop_column = !var.destructive
}
}
}
`
pathC := filepath.Join(p, "atlas.hcl")
require.NoError(t, os.WriteFile(pathC, []byte(h), 0600))
pathS := filepath.Join(p, "schema.sql")
require.NoError(t, os.WriteFile(pathS, []byte(`CREATE TABLE t(c1 int, c2 int);`), 0600))
pathD := t.TempDir()
cmd := migrateCmd()
cmd.AddCommand(migrateDiffCmd())
s, err := runCmd(
cmd, "diff", "initial",
"-c", "file://"+pathC,
"--env", "local",
"--var", "schema="+pathS,
"--var", "dir="+pathD,
)
require.NoError(t, err)
require.Empty(t, s)
d, err := migrate.NewLocalDir(pathD)
require.NoError(t, err)
files, err := d.Files()
require.NoError(t, err)
require.Len(t, files, 1)
require.Equal(t, "-- Create \"t\" table\nCREATE TABLE `t` (`c1` int NULL, `c2` int NULL);\n", string(files[0].Bytes()))
// Drop column should be skipped.
require.NoError(t, os.WriteFile(pathS, []byte(`CREATE TABLE t(c1 int);`), 0600))
cmd = migrateCmd()
cmd.AddCommand(migrateDiffCmd())
s, err = runCmd(
cmd, "diff", "no_change",
"-c", "file://"+pathC,
"--env", "local",
"--var", "schema="+pathS,
"--var", "dir="+pathD,
)
require.NoError(t, err)
require.Equal(t, "The migration directory is synced with the desired state, no changes to be made\n", s)
files, err = d.Files()
require.NoError(t, err)
require.Len(t, files, 1)
// Column is dropped when destructive is true.
cmd = migrateCmd()
cmd.AddCommand(migrateDiffCmd())
s, err = runCmd(
cmd, "diff", "second",
"-c", "file://"+pathC,
"--env", "local",
"--var", "schema="+pathS,
"--var", "dir="+pathD,
"--var", "destructive=true",
)
require.NoError(t, err)
require.Empty(t, s)
files, err = d.Files()
require.NoError(t, err)
require.Len(t, files, 2)
})
t.Run("TemplateDir", func(t *testing.T) {
var (
h = `
variable "default" {
type = string
default = "Default"
}
variable "schema_path" {
type = string
}
variable "migrations_path" {
type = string
}
data "hcl_schema" "app" {
path = var.schema_path
vars = {
default = var.default
}
}
data "template_dir" "app" {
path = var.migrations_path
vars = {
default = var.default
}
}
env "local" {
src = data.hcl_schema.app.url
dev = "sqlite://file?mode=memory&_fk=1"
migration {
dir = data.template_dir.app.url
}
}
`
p, md = t.TempDir(), t.TempDir()
cfg, state = filepath.Join(p, "atlas.hcl"), filepath.Join(p, "schema.hcl")
)
err := os.WriteFile(cfg, []byte(h), 0600)
require.NoError(t, err)
err = os.WriteFile(state, []byte(`variable "default" { type = string }
schema "main" {}
table "users" {
schema = schema.main
column "c" {
type = text
default = var.default
}
}
`), 0600)
require.NoError(t, err)
dir, err := migrate.NewLocalDir(md)
require.NoError(t, err)
err = dir.WriteFile("1.sql", []byte(`create table users (c text default "{{ .default }}" NOT NULL);`))
require.NoError(t, err)
cmd := migrateCmd()
cmd.AddCommand(migrateHashCmd())
_, err = runCmd(
cmd, "hash",
"--dir", "file://"+md,
)
require.NoError(t, err)
f, err := dir.Open(migrate.HashFileName)
require.NoError(t, err)
b, err := io.ReadAll(f)
require.NoError(t, err)
require.NotEmpty(t, b)
cmd = migrateCmd()
cmd.AddCommand(migrateDiffCmd())
s, err := runCmd(
cmd, "diff",
"-c", "file://"+cfg,
"--env", "local",
"--var", "migrations_path="+md,
"--var", "schema_path="+state,
)
// Desired state and migration directory are in sync.
require.NoError(t, err)
require.Equal(t, "The migration directory is synced with the desired state, no changes to be made\n", s)
f, err = dir.Open(migrate.HashFileName)
require.NoError(t, err)
nb, err := io.ReadAll(f)
require.NoError(t, err)
require.Equal(t, b, nb, "hash file should not be updated")
// Update the desired state and run diff again.
err = os.WriteFile(state, []byte(`variable "default" { type = string }
schema "main" {}
table "users" {
schema = schema.main
column "c" {
type = text
default = var.default
}
column "d" {
type = text
}
}
`), 0600)
require.NoError(t, err)
_, err = runCmd(
cmd, "diff",
"-c", "file://"+cfg,
"--env", "local",
"--var", "migrations_path="+md,
"--var", "schema_path="+state,
)
require.NoError(t, err)
// Check files.
files, err := dir.Files()
require.NoError(t, err)
require.Len(t, files, 2)
require.Equal(t, "1.sql", files[0].Name())
require.Equal(t, `create table users (c text default "{{ .default }}" NOT NULL);`, string(files[0].Bytes()), "should not update template files")
require.Equal(t, "-- Add column \"d\" to table: \"users\"\nALTER TABLE `users` ADD COLUMN `d` text NOT NULL;\n", string(files[1].Bytes()))
// Ensure the sum file is consistent.
f, err = dir.Open(migrate.HashFileName)
require.NoError(t, err)
before, err := io.ReadAll(f)
require.NoError(t, err)
cmd = migrateCmd()
cmd.AddCommand(migrateHashCmd())
_, err = runCmd(
cmd, "hash",
"--dir", "file://"+md,
)
require.NoError(t, err)
f, err = dir.Open(migrate.HashFileName)
require.NoError(t, err)
after, err := io.ReadAll(f)
require.NoError(t, err)
require.Equal(t, before, after)
})
}
func TestMigrate_StatusJSON(t *testing.T) {
p := t.TempDir()
s, err := runCmd(
migrateStatusCmd(),
"--dir", "file://"+p,
"-u", openSQLite(t, ""),
"--format", "{{ json .Env.Driver }}",
)
require.NoError(t, err)
require.Equal(t, `"sqlite"`, s)
}
func TestMigrate_Set(t *testing.T) {
u := fmt.Sprintf("sqlite://file:%s?_fk=1", filepath.Join(t.TempDir(), "test.db"))
_, err := runCmd(
migrateApplyCmd(),
"--dir", "file://testdata/sqlite",
"--url", u,
)
require.NoError(t, err)
s, err := runCmd(
migrateSetCmd(),
"--dir", "file://testdata/sqlite",
"-u", u,
"20220318104614",
)
require.NoError(t, err)
require.Equal(t, `Current version is 20220318104614 (1 removed):
- 20220318104615 (second)
`, s)
s, err = runCmd(
migrateSetCmd(),
"--dir", "file://testdata/sqlite",
"-u", u,
"20220318104615",
)
require.NoError(t, err)
require.Equal(t, `Current version is 20220318104615 (1 set):
+ 20220318104615 (second)
`, s)
s, err = runCmd(
migrateSetCmd(),
"--dir", "file://testdata/baseline1",
"-u", u,
)
require.NoError(t, err)
require.Equal(t, `Current version is 1 (1 set, 2 removed):
+ 1 (baseline)
- 20220318104614 (initial)
- 20220318104615 (second)
`, s)
s, err = runCmd(
migrateSetCmd(),
"--dir", filepath.Join("file://", t.TempDir()), // empty dir.
"-u", u,
)
require.NoError(t, err)
require.Equal(t, `All revisions deleted (1 in total):
- 1 (baseline)
`, s)
// Empty database.
u = fmt.Sprintf("sqlite://file:%s?_fk=1", filepath.Join(t.TempDir(), "test.db"))
_, err = runCmd(
migrateSetCmd(),
"--dir", "file://testdata/sqlite",
"-u", u,
)
require.EqualError(t, err, "accepts 1 arg(s), received 0")
s, err = runCmd(
migrateSetCmd(),
"--dir", "file://testdata/sqlite",
"-u", u,
"20220318104614",
)
require.NoError(t, err)
require.Equal(t, `Current version is 20220318104614 (1 set):
+ 20220318104614 (initial)
`, s)
}
func TestMigrate_New(t *testing.T) {
var (
p = t.TempDir()
v = time.Now().UTC().Format("20060102150405")
)
s, err := runCmd(migrateNewCmd(), "--dir", "file://"+p)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+".sql"))
require.FileExists(t, filepath.Join(p, "atlas.sum"))
require.Equal(t, 2, countFiles(t, p))
s, err = runCmd(migrateNewCmd(), "my-migration-file", "--dir", "file://"+p)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+"_my-migration-file.sql"))
require.FileExists(t, filepath.Join(p, "atlas.sum"))
require.Equal(t, 3, countFiles(t, p))
p = t.TempDir()
s, err = runCmd(migrateNewCmd(), "golang-migrate", "--dir", "file://"+p, "--dir-format", migrate2.FormatGolangMigrate)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+"_golang-migrate.up.sql"))
require.FileExists(t, filepath.Join(p, v+"_golang-migrate.down.sql"))
require.Equal(t, 3, countFiles(t, p))
p = t.TempDir()
s, err = runCmd(migrateNewCmd(), "goose", "--dir", "file://"+p+"?format="+migrate2.FormatGoose)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+"_goose.sql"))
require.Equal(t, 2, countFiles(t, p))
p = t.TempDir()
s, err = runCmd(migrateNewCmd(), "flyway", "--dir", "file://"+p+"?format="+migrate2.FormatFlyway)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, fmt.Sprintf("V%s__%s.sql", v, migrate2.FormatFlyway)))
require.FileExists(t, filepath.Join(p, fmt.Sprintf("U%s__%s.sql", v, migrate2.FormatFlyway)))
require.Equal(t, 3, countFiles(t, p))
p = t.TempDir()
s, err = runCmd(migrateNewCmd(), "liquibase", "--dir", "file://"+p+"?format="+migrate2.FormatLiquibase)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+"_liquibase.sql"))
require.Equal(t, 2, countFiles(t, p))
p = t.TempDir()
s, err = runCmd(migrateNewCmd(), "dbmate", "--dir", "file://"+p+"?format="+migrate2.FormatDBMate)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+"_dbmate.sql"))
require.Equal(t, 2, countFiles(t, p))
f := filepath.Join("testdata", "mysql", "new.sql")
require.NoError(t, os.WriteFile(f, []byte("contents"), 0600))
t.Cleanup(func() { os.Remove(f) })
s, err = runCmd(migrateNewCmd(), "--dir", "file://testdata/mysql")
require.NotZero(t, s)
require.Error(t, err)
t.Run("Edit", func(t *testing.T) {
p := t.TempDir()
require.NoError(t, os.Setenv("EDITOR", "echo 'contents' >"))
t.Cleanup(func() { require.NoError(t, os.Unsetenv("EDITOR")) })
s, err = runCmd(migrateNewCmd(), "--dir", "file://"+p, "--edit")
files, err := os.ReadDir(p)
require.NoError(t, err)
require.Len(t, files, 2)
b, err := os.ReadFile(filepath.Join(p, files[0].Name()))
require.NoError(t, err)
require.Equal(t, "contents\n", string(b))
require.Equal(t, "atlas.sum", files[1].Name())
})
}
func TestMigrate_Validate(t *testing.T) {
// Without re-playing.
s, err := runCmd(migrateValidateCmd(), "--dir", "file://testdata/mysql")
require.Zero(t, s)
require.NoError(t, err)
f := filepath.Join("testdata", "mysql", "new.sql")
require.NoError(t, os.WriteFile(f, []byte("contents"), 0600))
t.Cleanup(func() { os.Remove(f) })
s, err = runCmd(migrateValidateCmd(), "--dir", "file://testdata/mysql")
require.NotZero(t, s)
require.Error(t, err)
require.NoError(t, os.Remove(f))
// Replay migration files if a dev-url is given.
p := t.TempDir()
require.NoError(t, os.WriteFile(filepath.Join(p, "1_initial.sql"), []byte("create table t1 (c1 int)"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(p, "2_second.sql"), []byte("create table t2 (c2 int)"), 0644))
_, err = runCmd(migrateHashCmd(), "--dir", "file://"+p)
require.NoError(t, err)
s, err = runCmd(
migrateValidateCmd(),
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
)
require.Zero(t, s)
require.NoError(t, err)
// Should fail since the files are not compatible with SQLite.
_, err = runCmd(migrateValidateCmd(), "--dir", "file://testdata/mysql", "--dev-url", openSQLite(t, ""))
require.Error(t, err)
// Will report detailed information when there is a checksum mismatch.
p = t.TempDir()
require.NoError(t, os.WriteFile(filepath.Join(p, "1_initial.sql"), []byte("create table t1 (c1 int)"), 0644))
s, err = runCmd(migrateValidateCmd(), "--dir", "file://"+p)
require.ErrorIs(t, err, migrate.ErrChecksumNotFound)
require.Contains(t, s, "You have a checksum error")
_, err = runCmd(migrateHashCmd(), "--dir", "file://"+p)
require.NoError(t, err)
require.NoError(t, os.WriteFile(filepath.Join(p, "2_second.sql"), []byte("create table t2 (c2 int)"), 0644))
s, err = runCmd(migrateValidateCmd(), "--dir", "file://"+p)
csErr := &migrate.ChecksumError{}
require.ErrorAs(t, err, &csErr)
require.Equal(t, 3, csErr.Line)
require.Equal(t, "2_second.sql", csErr.File)
require.Equal(t, migrate.ReasonAdded, csErr.Reason)
require.Contains(t, s, "You have a checksum error")
require.Contains(t, s, "L3: 2_second.sql was added")
}
func TestMigrate_Hash(t *testing.T) {
s, err := runCmd(migrateHashCmd(), "--dir", "file://testdata/mysql")
require.Zero(t, s)
require.NoError(t, err)
// Prints a warning if --force flag is still used.
s, err = runCmd(migrateHashCmd(), "--dir", "file://testdata/mysql", "--force")
require.NoError(t, err)
require.Equal(t, "Flag --force has been deprecated, you can safely omit it.\n", s)
p := t.TempDir()
err = copyFile(filepath.Join("testdata", "mysql", "20220318104614_initial.sql"), filepath.Join(p, "20220318104614_initial.sql"))
require.NoError(t, err)
s, err = runCmd(migrateHashCmd(), "--dir", "file://"+p)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, "atlas.sum"))
d, err := os.ReadFile(filepath.Join(p, "atlas.sum"))
require.NoError(t, err)
dir, err := migrate.NewLocalDir(p)
require.NoError(t, err)
sum, err := dir.Checksum()
require.NoError(t, err)
b, err := sum.MarshalText()
require.NoError(t, err)
require.Equal(t, d, b)
p = t.TempDir()
require.NoError(t, copyFile(
filepath.Join("testdata", "mysql", "20220318104614_initial.sql"),
filepath.Join(p, "20220318104614_initial.sql"),
))
s, err = runCmd(migrateHashCmd(), "--dir", "file://"+os.Getenv("MIGRATION_DIR"))
require.NotZero(t, s)
require.Error(t, err)
}
func TestMigrate_Lint(t *testing.T) {
p := t.TempDir()
s, err := runCmd(
migrateLintCmd(),
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"--latest", "1",
)
require.NoError(t, err)
require.Empty(t, s)
err = os.WriteFile(filepath.Join(p, "1.sql"), []byte("CREATE TABLE t(c int);"), 0600)
require.NoError(t, err)
err = os.WriteFile(filepath.Join(p, "2.sql"), []byte("DROP TABLE t;"), 0600)
require.NoError(t, err)
s, err = runCmd(
migrateLintCmd(),
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"--latest", "1",
)
require.Error(t, err)
require.Regexp(t, `Analyzing changes from version 1 to 2 \(1 migration in total\):
-- analyzing version 2
-- destructive changes detected:
-- L1: Dropping table "t" https://atlasgo.io/lint/analyzers#DS102
-- suggested fix:
-> Add a pre-migration check to ensure table "t" is empty before dropping it
-- ok \(.+\)
-------------------------
-- .+
-- 1 version with errors
-- 1 schema change
-- 1 diagnostic
`, s)
s, err = runCmd(
migrateLintCmd(),
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"--latest", "1",
"--log", "{{ range .Files }}{{ .Name }}{{ end }}", // Backward compatibility with old flag name.
)
require.Error(t, err)
require.Equal(t, "2.sql", s)
t.Run("FromConfig", func(t *testing.T) {
cfg := filepath.Join(p, "atlas.hcl")
err := os.WriteFile(cfg, []byte(`
variable "error" {
type = bool
default = false
}
lint {
latest = 1
destructive {
error = var.error
}
}
`), 0600)
require.NoError(t, err)
cmd := migrateCmd()
cmd.AddCommand(migrateLintCmd())
s, err := runCmd(
cmd, "lint",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"-c", "file://"+cfg,
)
require.NoError(t, err)
require.Regexp(t, `Analyzing changes from version 1 to 2 \(1 migration in total\):
-- analyzing version 2
-- destructive changes detected:
-- L1: Dropping table "t" https://atlasgo.io/lint/analyzers#DS102
-- suggested fix:
-> Add a pre-migration check to ensure table "t" is empty before dropping it
-- ok \(.+\)
-------------------------
-- .+
-- 1 version with warnings
-- 1 schema change
-- 1 diagnostic
`, s)
cmd = migrateCmd()
cmd.AddCommand(migrateLintCmd())
s, err = runCmd(
cmd, "lint",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"-c", "file://"+cfg,
"--var", "error=true",
)
require.Error(t, err)
require.Regexp(t, `Analyzing changes from version 1 to 2 \(1 migration in total\):
-- analyzing version 2
-- destructive changes detected:
-- L1: Dropping table "t" https://atlasgo.io/lint/analyzers#DS102
-- suggested fix:
-> Add a pre-migration check to ensure table "t" is empty before dropping it
-- ok (.+)
-------------------------
-- .+
-- 1 version with errors
-- 1 schema change
-- 1 diagnostic
`, s)
})
// Change files to golang-migrate format.
require.NoError(t, os.Rename(filepath.Join(p, "1.sql"), filepath.Join(p, "1.up.sql")))
require.NoError(t, os.Rename(filepath.Join(p, "2.sql"), filepath.Join(p, "1.down.sql")))
s, err = runCmd(
migrateLintCmd(),
"--dir", "file://"+p+"?format="+migrate2.FormatGolangMigrate,
"--dev-url", openSQLite(t, ""),
"--latest", "2",
"--format", "{{ range .Files }}{{ .Name }}:{{ len .Reports }}{{ end }}",
)
require.NoError(t, err)
require.Equal(t, "1.up.sql:0", s)
s, err = runCmd(
migrateLintCmd(),
"--dir", "file://"+p+"?format="+migrate2.FormatGolangMigrate,
"--dev-url", openSQLite(t, ""),
"--latest", "2",
"--format", "{{ range .Files }}{{ .Name }}:{{ len .Reports }}{{ end }}",
"--dir-format", migrate2.FormatGolangMigrate,
)
require.NoError(t, err)
require.Equal(t, "1.up.sql:0", s)
// Invalid files.
err = os.WriteFile(filepath.Join(p, "2.up.sql"), []byte("BORING"), 0600)
require.NoError(t, err)
s, err = runCmd(
migrateLintCmd(),
"--dir", "file://"+p+"?format="+migrate2.FormatGolangMigrate,
"--dev-url", openSQLite(t, ""),
"--latest", "1",
)
require.Error(t, err)
require.Regexp(t, `Analyzing changes from version 1.up to 2.up \(1 migration in total\):
Error: executing statement: BORING: near "BORING": syntax error
-------------------------
-- .+
-- 1 version with errors
`, s)
}
const testSchema = `
schema "main" {
}
table "table" {
schema = schema.main
column "col" {
type = int
comment = "column comment"
}
column "age" {
type = int
}
column "price1" {
type = int
}
column "price2" {
type = int
}
column "account_name" {
type = varchar(32)
null = true
}
column "created_at" {
type = datetime
default = sql("current_timestamp")
}
primary_key {
columns = [table.table.column.col]
}
index "index" {
unique = true
columns = [
table.table.column.col,
table.table.column.age,
]
}
foreign_key "accounts" {
columns = [
table.table.column.account_name,
]
ref_columns = [
table.accounts.column.name,
]
on_delete = SET_NULL
on_update = "NO_ACTION"
}
check "positive price" {
expr = "price1 > 0"
}
check {
expr = "price1 <> price2"
}
check {
expr = "price2 <> price1"
}
comment = "table comment"
}
table "accounts" {
schema = schema.main
column "name" {
type = varchar(32)
}
column "unsigned_float" {
type = float(10)
unsigned = true
}
column "unsigned_decimal" {
type = decimal(10, 2)
unsigned = true
}
primary_key {
columns = [table.accounts.column.name]
}
}`
func hclURL(t *testing.T) string {
p := t.TempDir()
require.NoError(t, os.WriteFile(filepath.Join(p, "schema.hcl"), []byte(testSchema), 0600))
return "file://" + filepath.Join(p, "schema.hcl")
}
func copyFile(src, dst string) error {
sf, err := os.Open(src)
if err != nil {
return err
}
defer sf.Close()
df, err := os.Create(dst)
if err != nil {
return err
}
defer df.Close()
_, err = io.Copy(df, sf)
return err
}
type sqliteLockerDriver struct{ migrate.Driver }
var errLock = errors.New("lockErr")
func (d *sqliteLockerDriver) Lock(context.Context, string, time.Duration) (schema.UnlockFunc, error) {
return func() error { return nil }, errLock
}
func countFiles(t *testing.T, p string) int {
files, err := os.ReadDir(p)
require.NoError(t, err)
return len(files)
}
func sed(t *testing.T, r, p string) {
args := []string{"-i"}
if runtime.GOOS == "darwin" {
args = append(args, ".bk")
}
buf, err := exec.Command("sed", append(args, r, p)...).CombinedOutput()
require.NoError(t, err, string(buf))
}
func lines(f migrate.File) []string {
return strings.Split(strings.TrimSpace(string(f.Bytes())), "\n")
}
================================================
FILE: cmd/atlas/internal/cmdapi/project.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"context"
"fmt"
"net/url"
"os"
"path/filepath"
"reflect"
"strings"
"sync"
"ariga.io/atlas/cmd/atlas/internal/cloudapi"
"ariga.io/atlas/cmd/atlas/internal/cmdext"
cmdmigrate "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/schemahcl"
"ariga.io/atlas/sql/schema"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclparse"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/spf13/cobra"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
)
type (
// Env represents an Atlas environment.
Env struct {
// Name for this environment.
Name string `spec:"name,name"`
// URL of the database.
URL string `spec:"url"`
// URL of the dev-database for this environment.
// See: https://atlasgo.io/dev-database
DevURL string `spec:"dev"`
// List of schemas in this database that are managed by Atlas.
Schemas []string `spec:"schemas"`
// Exclude defines a list of glob patterns used to filter
// resources on inspection.
Exclude []string `spec:"exclude"`
// Include defines a list of glob patterns used to keep
// resources on inspection.
Include []string `spec:"include"`
// Schema containing the schema configuration of the env.
Schema *Schema `spec:"schema"`
// Migration containing the migration configuration of the env.
Migration *Migration `spec:"migration"`
// Diff policy of the environment.
Diff *Diff `spec:"diff"`
// Lint policy of the environment.
Lint *Lint `spec:"lint"`
// Format of the environment.
Format Format `spec:"format"`
// Test configuration of the environment.
Test *Test `spec:"test"`
schemahcl.DefaultExtension
cloud *cmdext.AtlasConfig
config *Project
}
// Migration represents the migration directory for the Env.
Migration struct {
Dir string `spec:"dir"`
Exclude []string `spec:"exclude"`
Format string `spec:"format"`
Baseline string `spec:"baseline"`
ExecOrder string `spec:"exec_order"`
LockTimeout string `spec:"lock_timeout"`
RevisionsSchema string `spec:"revisions_schema"`
Repo *Repo `spec:"repo"`
}
// Schema represents a schema in the registry.
Schema struct {
// The extension holds the "src" attribute.
// It can be a string, or a list of strings.
schemahcl.DefaultExtension
Repo *Repo `spec:"repo"`
}
// Repo represents a repository in the schema registry
// for a schema or migrations directory.
Repo struct {
Name string `spec:"name"` // Name of the repository.
}
// Lint represents the configuration of migration linting.
Lint struct {
// Format configures the --format option.
Format string `spec:"log"`
// Latest configures the --latest option.
Latest int `spec:"latest"`
Git struct {
// Dir configures the --git-dir option.
Dir string `spec:"dir"`
// Base configures the --git-base option.
Base string `spec:"base"`
} `spec:"git"`
// Review defines when Atlas will ask the user to review and approve the changes.
Review string `spec:"review"`
schemahcl.DefaultExtension
}
// Diff represents the schema diffing policy.
Diff struct {
// SkipChanges configures the skip changes policy.
SkipChanges *SkipChanges `spec:"skip"`
schemahcl.DefaultExtension
}
// Test represents the test configuration of a project or environment.
Test struct {
// Schema represents the 'schema test' configuration.
Schema struct {
Src []string `spec:"src"`
Vars Vars `spec:"vars"`
} `spec:"schema"`
// Migrate represents the 'migrate test' configuration.
Migrate struct {
Src []string `spec:"src"`
Vars Vars `spec:"vars"`
} `spec:"migrate"`
}
// SkipChanges represents the skip changes policy.
SkipChanges struct {
AddSchema bool `spec:"add_schema"`
DropSchema bool `spec:"drop_schema"`
ModifySchema bool `spec:"modify_schema"`
AddTable bool `spec:"add_table"`
DropTable bool `spec:"drop_table"`
ModifyTable bool `spec:"modify_table"`
RenameTable bool `spec:"rename_table"`
AddColumn bool `spec:"add_column"`
DropColumn bool `spec:"drop_column"`
ModifyColumn bool `spec:"modify_column"`
AddIndex bool `spec:"add_index"`
DropIndex bool `spec:"drop_index"`
ModifyIndex bool `spec:"modify_index"`
AddForeignKey bool `spec:"add_foreign_key"`
DropForeignKey bool `spec:"drop_foreign_key"`
ModifyForeignKey bool `spec:"modify_foreign_key"`
AddView bool `spec:"add_view"`
DropView bool `spec:"drop_view"`
ModifyView bool `spec:"modify_view"`
RenameView bool `spec:"rename_view"`
AddFunc bool `spec:"add_func"`
DropFunc bool `spec:"drop_func"`
ModifyFunc bool `spec:"modify_func"`
RenameFunc bool `spec:"rename_func"`
AddProc bool `spec:"add_proc"`
DropProc bool `spec:"drop_proc"`
ModifyProc bool `spec:"modify_proc"`
RenameProc bool `spec:"rename_proc"`
AddTrigger bool `spec:"add_trigger"`
DropTrigger bool `spec:"drop_trigger"`
ModifyTrigger bool `spec:"modify_trigger"`
RenameTrigger bool `spec:"rename_trigger"`
RenameConstraint bool `spec:"rename_constraint"`
schemahcl.DefaultExtension
}
// Format represents the output formatting configuration of an environment.
Format struct {
Migrate struct {
// Apply configures the formatting for 'migrate apply'.
Apply string `spec:"apply"`
// Down configures the formatting for 'migrate down'.
Down string `spec:"down"`
// Lint configures the formatting for 'migrate lint'.
Lint string `spec:"lint"`
// Status configures the formatting for 'migrate status'.
Status string `spec:"status"`
// Apply configures the formatting for 'migrate diff'.
Diff string `spec:"diff"`
} `spec:"migrate"`
Schema struct {
// Clean configures the formatting for 'schema clean'.
Clean string `spec:"clean"`
// Inspect configures the formatting for 'schema inspect'.
Inspect string `spec:"inspect"`
// Apply configures the formatting for 'schema apply'.
Apply string `spec:"apply"`
// Apply configures the formatting for 'schema diff'.
Diff string `spec:"diff"`
// Push configures the formatting for 'schema push'.
Push string `spec:"push"`
} `spec:"schema"`
schemahcl.DefaultExtension
}
)
// envScheme defines the scheme that can be used to reference env attributes.
const envAttrScheme = "env"
// MigrationRepo returns the migration repository name, if set.
func (e *Env) MigrationRepo() (s string) {
if e != nil && e.Migration != nil && e.Migration.Repo != nil {
s = e.Migration.Repo.Name
}
return
}
// MigrationExclude returns the exclusion patterns of the migration directory.
func (e *Env) MigrationExclude() []string {
if e != nil && e.Migration != nil {
return e.Migration.Exclude
}
return nil
}
// SchemaRepo returns the desired schema repository name, if set.
func (e *Env) SchemaRepo() (s string) {
if e != nil && e.Schema != nil && e.Schema.Repo != nil {
s = e.Schema.Repo.Name
}
return
}
// LintReview returns the review mode for the lint command.
func (e *Env) LintReview() string {
if e != nil && e.Lint != nil && e.Lint.Review != "" {
return e.Lint.Review
}
return ReviewAlways
}
// VarFromURL returns the string variable (env attribute) from the URL.
func (e *Env) VarFromURL(s string) (string, error) {
u, err := url.Parse(s)
if err != nil {
return "", err
}
if u.Host == "" || u.Path != "" || u.RawQuery != "" {
return "", fmt.Errorf("invalid env:// variable %q", s)
}
var sv string
switch u.Host {
case "url":
sv = e.URL
case "dev":
sv = e.DevURL
case "src", "schema.src":
var (
ok bool
attr *schemahcl.Attr
)
switch {
case u.Host == "src":
attr, ok = e.Attr("src")
case e.Schema != nil:
attr, ok = e.Schema.Attr("src")
}
if !ok {
return "", fmt.Errorf("env://%s: no src attribute defined in env %q", u.Host, e.Name)
}
switch attr.V.Type() {
case cty.String:
s, err := attr.String()
if err != nil {
return "", fmt.Errorf("env://%s: %w", u.Host, err)
}
return s, nil
case cty.List(cty.String):
vs, err := attr.Strings()
if err != nil {
return "", fmt.Errorf("env://%s: %w", u.Host, err)
}
if len(vs) != 0 {
return "", fmt.Errorf("env://%s: expect one schema in env %q, got %d", u.Host, e.Name, len(vs))
}
return vs[0], nil
default:
return "", fmt.Errorf("env://%s: src attribute must be a string or list of strings, got %s", u.Host, attr.V.Type().FriendlyName())
}
case "migration.dir":
if e.Migration == nil || e.Migration.Dir == "" {
return "", fmt.Errorf("env://%s: no migration dir defined in env %q", u.Host, e.Name)
}
sv = e.Migration.Dir
default:
attr, ok := e.Attr(u.Host)
if !ok {
return "", fmt.Errorf("env://%s (attribute) not found in env.%s", u.Host, e.Name)
}
if sv, err = attr.String(); err != nil {
return "", fmt.Errorf("env://%s: %w", u.Host, err)
}
}
if strings.HasPrefix(sv, envAttrScheme+"://") {
return "", fmt.Errorf("env://%s (attribute) cannot reference another env://", s)
}
return sv, nil
}
// support backward compatibility with the 'log' attribute.
func (e *Env) remainedLog() error {
r, ok := e.Remain().Resource("log")
if ok {
return r.As(&e.Format)
}
return nil
}
// Extend allows extending environment blocks with
// a global one. For example:
//
// lint {
// log = < 0 {
opts = append(opts, schema.DiffSkipChanges(changes...))
}
return opts
}
// DiffOptions returns the diff options configured for the environment,
// or nil if no environment or diff policy were set.
func (e *Env) DiffOptions() []schema.DiffOption {
if e == nil || e.Diff == nil {
return nil
}
return e.Diff.Options()
}
// Sources returns the paths containing the Atlas desired schema.
// The "src" attribute predates the "schema" block. If the "schema"
// is defined, it takes precedence over the "src" attribute.
func (e *Env) Sources() ([]string, error) {
var (
ok bool
attr *schemahcl.Attr
)
if attr, ok = e.Attr("src"); !ok && e.Schema != nil {
attr, ok = e.Schema.Attr("src")
}
if !ok {
return nil, nil
}
switch attr.V.Type() {
case cty.String:
s, err := attr.String()
if err != nil {
return nil, err
}
return []string{s}, nil
case cty.List(cty.String):
return attr.Strings()
default:
return nil, fmt.Errorf("expected src to be either a string or strings, got: %s", attr.V.Type().FriendlyName())
}
}
// Vars returns the extra attributes stored in the Env as a map[string]cty.Value.
func (e *Env) Vars() map[string]cty.Value {
m := make(map[string]cty.Value, len(e.Extra.Attrs))
for _, attr := range e.Extra.Attrs {
if attr.K == "src" {
continue
}
m[attr.K] = attr.V
}
// For backward compatibility, we append the GlobalFlags as variables.
for k, v := range GlobalFlags.Vars {
if _, ok := m[k]; !ok {
m[k] = v
}
}
return m
}
// Extend allows extending environment blocks with
// a global one. For example:
//
// test {
// schema {
// src = [...]
// }
// }
//
// env "local" {
// ...
// test {
// schema {
// src = [...]
// }
// }
// }
func (t *Test) Extend(global *Test) *Test {
if t == nil {
return global
}
return t
}
// EnvByName parses and returns the project configuration with selected environments.
func EnvByName(cmd *cobra.Command, name string, vars map[string]cty.Value) (*Project, []*Env, error) {
envs := make(map[string][]*Env)
defer func() {
setEnvs(cmd.Context(), envs[name])
}()
if p, e, ok := envsCache.load(GlobalFlags.ConfigURL, name, vars); ok {
return p, e, maySetLoginContext(cmd, p)
}
u, err := url.Parse(GlobalFlags.ConfigURL)
if err != nil {
return nil, nil, err
}
switch {
case u.Scheme == "":
return nil, nil, fmt.Errorf("missing scheme for config file. Did you mean file://%s?", u)
case u.Scheme != "file":
return nil, nil, fmt.Errorf("unsupported config file driver %q", u.Scheme)
}
path := filepath.Join(u.Host, u.Path)
if _, err := os.Stat(path); err != nil {
if os.IsNotExist(err) {
err = fmt.Errorf("config file %q was not found: %w", path, err)
}
return nil, nil, err
}
project, err := parseConfig(cmd.Context(), path, name, vars)
if err != nil {
return nil, nil, err
}
// The atlas.hcl token predates 'atlas login' command. If exists,
// attach it to the context to indicate the user is authenticated.
if err := maySetLoginContext(cmd, project); err != nil {
return nil, nil, err
}
if err := project.Lint.remainedLog(); err != nil {
return nil, nil, err
}
for _, e := range project.Envs {
if e.Name == "" {
return nil, nil, fmt.Errorf("all envs must have names on file %q", path)
}
if _, err := e.Sources(); err != nil {
return nil, nil, err
}
if e.Migration == nil {
e.Migration = &Migration{}
}
if err := e.remainedLog(); err != nil {
return nil, nil, err
}
e.Diff = e.Diff.Extend(project.Diff)
e.Lint = e.Lint.Extend(project.Lint)
if err := e.Lint.remainedLog(); err != nil {
return nil, nil, err
}
e.Test = e.Test.Extend(project.Test)
envs[e.Name] = append(envs[e.Name], e)
}
envsCache.store(GlobalFlags.ConfigURL, name, vars, project, envs[name])
switch {
case name == "":
// If no env was selected,
// return only the project.
return project, nil, nil
case len(envs[name]) == 0:
return nil, nil, fmt.Errorf("env %q not defined in config file", name)
default:
return project, envs[name], nil
}
}
type (
envCacheK struct {
path, env, vars string
}
envCacheV struct {
p *Project
e []*Env
}
envCache struct {
sync.RWMutex
m map[envCacheK]envCacheV
}
)
var envsCache = &envCache{m: make(map[envCacheK]envCacheV)}
func (c *envCache) load(path, env string, vars Vars) (*Project, []*Env, bool) {
c.RLock()
v, ok := c.m[envCacheK{path: path, env: env, vars: vars.String()}]
c.RUnlock()
return v.p, v.e, ok
}
func (c *envCache) store(path, env string, vars Vars, p *Project, e []*Env) {
c.Lock()
c.m[envCacheK{path: path, env: env, vars: vars.String()}] = envCacheV{p: p, e: e}
c.Unlock()
}
const (
blockEnv = "env"
refAtlas = "atlas"
defaultConfigPath = "file://atlas.hcl"
)
func parseConfig(ctx context.Context, path, env string, vars map[string]cty.Value) (*Project, error) {
pr, err := partialParse(path, env)
if err != nil {
return nil, err
}
base, err := filepath.Abs(filepath.Dir(path))
if err != nil {
return nil, err
}
cloud := &cmdext.AtlasConfig{
Project: cloudapi.DefaultProjectName,
}
state := schemahcl.New(
append(
append(cmdext.SpecOptions, specOptions...),
cloud.InitBlock(),
schemahcl.WithContext(ctx),
schemahcl.WithScopedEnums("env.migration.format", cmdmigrate.Formats...),
schemahcl.WithScopedEnums("env.migration.exec_order", "LINEAR", "LINEAR_SKIP", "NON_LINEAR"),
schemahcl.WithScopedEnums("env.lint.review", ReviewModes...),
schemahcl.WithScopedEnums("lint.review", ReviewModes...),
schemahcl.WithVariables(map[string]cty.Value{
refAtlas: cty.ObjectVal(map[string]cty.Value{
blockEnv: cty.StringVal(env),
}),
}),
schemahcl.WithFunctions(map[string]function.Function{
"file": schemahcl.MakeFileFunc(base),
"glob": schemahcl.MakeGlobFunc(base),
"fileset": schemahcl.MakeFileSetFunc(base),
"getenv": getEnvFunc,
}),
)...,
)
p := &Project{Lint: &Lint{}, Diff: &Diff{}, cloud: cloud}
if err := state.Eval(pr, p, vars); err != nil {
return nil, err
}
for _, e := range p.Envs {
e.config, e.cloud = p, cloud
}
return p, nil
}
func init() {
cloudapi.SetVersion(version, flavor)
schemahcl.Register(blockEnv, &Env{})
}
func partialParse(path, env string) (*hclparse.Parser, error) {
parser := hclparse.NewParser()
fi, err := parser.ParseHCLFile(path)
if err != nil {
return nil, err
}
var labeled, nonlabeled, used []*hclsyntax.Block
for _, b := range fi.Body.(*hclsyntax.Body).Blocks {
switch b.Type {
case blockEnv:
switch n := len(b.Labels); {
// No env was selected.
case env == "" && n == 0:
// Exact env was selected.
case n == 1 && b.Labels[0] == env:
labeled = append(labeled, b)
// Dynamic env selection.
case n == 0 && b.Body != nil && b.Body.Attributes[schemahcl.AttrName] != nil:
x := b.Body.Attributes[schemahcl.AttrName].Expr
if x != nil && schemahcl.UseTraversal(x, hcl.Traversal{
hcl.TraverseRoot{Name: refAtlas},
hcl.TraverseAttr{Name: blockEnv},
}) {
nonlabeled = append(nonlabeled, b)
}
}
default:
used = append(used, b)
}
}
// Labeled blocks take precedence
// over non-labeled env blocks.
switch {
case len(labeled) > 0:
used = append(used, labeled...)
case len(nonlabeled) > 0:
used = append(used, nonlabeled...)
}
fi.Body = &hclsyntax.Body{
Blocks: used,
Attributes: fi.Body.(*hclsyntax.Body).Attributes,
}
return parser, nil
}
// Review modes for 'schema apply'.
const (
ReviewAlways = "ALWAYS" // Always review changes. The default mode.
ReviewWarning = "WARNING" // Review changes only if there are any diagnostics (including warnings).
ReviewError = "ERROR" // Review changes only if there are severe diagnostics (error level).
)
var ReviewModes = []string{ReviewAlways, ReviewWarning, ReviewError}
// getEnvFunc is a custom HCL function that returns
// the value of an environment variable.
var getEnvFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "key",
Type: cty.String,
},
},
Type: function.StaticReturnType(cty.String),
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
return cty.StringVal(os.Getenv(args[0].AsString())), nil
},
})
================================================
FILE: cmd/atlas/internal/cmdapi/project_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"context"
"fmt"
"os"
"path/filepath"
"sort"
"testing"
"ariga.io/atlas/cmd/atlas/internal/cloudapi"
"ariga.io/atlas/cmd/atlas/internal/cmdext"
cmdmigrate "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/schemahcl"
"ariga.io/atlas/sql/schema"
"github.com/spf13/cobra"
"github.com/stretchr/testify/require"
"github.com/zclconf/go-cty/cty"
)
func TestEnvByName(t *testing.T) {
d := t.TempDir()
require.NoError(t, os.WriteFile(filepath.Join(d, "local.txt"), []byte("text"), 0600))
h := `
variable "name" {
type = string
default = "hello"
}
locals {
envName = atlas.env
emptyEnv = getenv("NOT_SET")
opened = file("local.txt")
}
lint {
review = ERROR
destructive {
error = true
}
// Backwards compatibility with old attribute.
log = < 1 {
return nil, fmt.Errorf("multiple envs found for %q", name)
}
return envs[0], nil
}
}
func schemaFlagsFromConfig(cmd *cobra.Command) error {
env, err := selectEnv(cmd)
if err != nil {
return err
}
return setSchemaEnvFlags(cmd, env)
}
func setSchemaEnvFlags(cmd *cobra.Command, env *Env) error {
if err := maySetFlag(cmd, flagDevURL, env.DevURL); err != nil {
return err
}
srcs, err := env.Sources()
if err != nil {
return err
}
srcs = fixFileURLs(srcs)
if err := maySetFlag(cmd, flagFile, strings.Join(srcs, ",")); err != nil {
return err
}
if err := maySetFlag(cmd, flagSchema, strings.Join(env.Schemas, ",")); err != nil {
return err
}
if err := maySetFlag(cmd, flagExclude, strings.Join(env.Exclude, ",")); err != nil {
return err
}
if err := maySetFlag(cmd, flagInclude, strings.Join(env.Include, ",")); err != nil {
return err
}
switch cmd.Name() {
case "clean":
if err := maySetFlag(cmd, flagURL, env.URL); err != nil {
return err
}
if err := maySetFlag(cmd, flagFormat, env.Format.Schema.Clean); err != nil {
return err
}
case "inspect":
if err := maySetFlag(cmd, flagURL, env.URL); err != nil {
return err
}
if err := maySetFlag(cmd, flagFormat, env.Format.Schema.Inspect); err != nil {
return err
}
case "apply":
if err := maySetFlag(cmd, flagURL, env.URL); err != nil {
return err
}
if err := maySetFlag(cmd, flagFormat, env.Format.Schema.Apply); err != nil {
return err
}
case "diff":
if err := maySetFlag(cmd, flagFormat, env.Format.Schema.Diff); err != nil {
return err
}
case "push":
if err := maySetFlag(cmd, flagURL, strings.Join(srcs, ",")); err != nil {
return err
}
if err := maySetFlag(cmd, flagFormat, env.Format.Schema.Push); err != nil {
return err
}
case "test":
// Give the "src" precedence over the "url" argument.
if len(srcs) > 0 {
if err := maySetFlag(cmd, flagURL, strings.Join(srcs, ",")); err != nil {
return err
}
} else if err := maySetFlag(cmd, flagURL, env.URL); err != nil {
return err
}
}
return nil
}
// diff holds the changes between two realms.
type diff struct {
from, to *schema.Realm
changes []schema.Change
}
func computeDiff(ctx context.Context, differ *sqlclient.Client, from, to *cmdext.StateReadCloser, opts ...schema.DiffOption) (*diff, error) {
current, err := from.ReadState(ctx)
if err != nil {
return nil, err
}
desired, err := to.ReadState(ctx)
if err != nil {
return nil, err
}
var changes []schema.Change
switch {
// In case an HCL file is compared against a specific database schema (not a realm).
case to.HCL && len(desired.Schemas) == 1 && from.Schema != "" && desired.Schemas[0].Name != from.Schema:
return nil, fmt.Errorf("mismatched HCL and database schemas: %q <> %q", from.Schema, desired.Schemas[0].Name)
// Compare realm if the desired state is an HCL file or both connections are not bound to a schema.
case from.HCL, to.HCL, from.Schema == "" && to.Schema == "":
changes, err = differ.RealmDiff(current, desired, opts...)
if err != nil {
return nil, err
}
case from.Schema == "" && to.Schema != "":
return nil, fmt.Errorf("cannot diff a schema %q with a database connection. See: https://atlasgo.io/url", to.Schema)
case from.Schema != "" && to.Schema == "":
return nil, fmt.Errorf("cannot diff a database connection with a schema %q. See: https://atlasgo.io/url", from.Schema)
default:
// SchemaDiff checks for name equality which is irrelevant in the case
// the user wants to compare their contents, reset them to allow the comparison.
current.Schemas[0].Name, desired.Schemas[0].Name = "", ""
changes, err = differ.SchemaDiff(current.Schemas[0], desired.Schemas[0], opts...)
if err != nil {
return nil, err
}
}
return &diff{
changes: changes,
from: current,
to: desired,
}, nil
}
const (
answerApply = "Apply"
answerAbort = "Abort"
)
// cmdPrompt returns a promptui.Select that uses the given command's input and output.
func cmdPrompt(cmd *cobra.Command) *promptui.Select {
return &promptui.Select{
Label: "Are you sure?",
HideHelp: true,
Stdin: io.NopCloser(cmd.InOrStdin()),
Stdout: nopBellCloser{cmd.OutOrStdout()},
}
}
func promptUser(cmd *cobra.Command) bool {
prompt := cmdPrompt(cmd)
prompt.Items = []string{answerApply, answerAbort}
_, result, err := prompt.Run()
if err != nil && !errors.Is(err, promptui.ErrInterrupt) {
// Fail in case of unexpected errors.
cobra.CheckErr(err)
}
return result == answerApply
}
type nopBellCloser struct{ io.Writer }
func (n nopBellCloser) Write(p []byte) (int, error) {
if len(p) == 1 && p[0] == readline.CharBell {
return 0, nil // Skip bell noise.
}
return n.Writer.Write(p)
}
func (nopBellCloser) Close() error { return nil }
func tasks(path string) ([]fmttask, error) {
var tasks []fmttask
stat, err := os.Stat(path)
if err != nil {
return nil, err
}
if !stat.IsDir() {
if strings.HasSuffix(path, ".hcl") {
tasks = append(tasks, fmttask{
path: path,
info: stat,
})
}
return tasks, nil
}
all, err := os.ReadDir(path)
if err != nil {
return nil, err
}
for _, f := range all {
if f.IsDir() {
continue
}
if strings.HasSuffix(f.Name(), ".hcl") {
i, err := f.Info()
if err != nil {
return nil, err
}
tasks = append(tasks, fmttask{
path: filepath.Join(path, f.Name()),
info: i,
})
}
}
return tasks, nil
}
type fmttask struct {
path string
info fs.FileInfo
}
// fmtFile tries to format a file and reports if formatting occurred.
func fmtFile(task fmttask) (bool, error) {
orig, err := os.ReadFile(task.path)
if err != nil {
return false, err
}
formatted := hclwrite.Format(orig)
if !bytes.Equal(formatted, orig) {
return true, os.WriteFile(task.path, formatted, task.info.Mode())
}
return false, nil
}
// fixFileURLs converts all file paths to a URL format, if not already.
// For example, "schema.hcl" to "file://schema.hcl".
func fixFileURLs(src []string) []string {
for i, s := range src {
if !isURL(s) {
src[i] = "file://" + s
}
}
return src
}
================================================
FILE: cmd/atlas/internal/cmdapi/schema_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"testing"
"ariga.io/atlas/cmd/atlas/internal/cmdlog"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
"github.com/stretchr/testify/require"
)
const (
unformatted = `block "x" {
x = 1
y = 2
}
`
formatted = `block "x" {
x = 1
y = 2
}
`
)
func TestSchema_Diff(t *testing.T) {
// Creates the missing table.
s, err := runCmd(
schemaDiffCmd(),
"--from", openSQLite(t, ""),
"--to", openSQLite(t, "create table t1 (id int);"),
)
require.NoError(t, err)
require.EqualValues(t, "-- Create \"t1\" table\nCREATE TABLE `t1` (`id` int NULL);\n", s)
// Format indentation one table.
s, err = runCmd(
schemaDiffCmd(),
"--from", openSQLite(t, ""),
"--to", openSQLite(t, "create table t1 (id int);"),
"--format", `{{ sql . " " }}`,
)
require.NoError(t, err)
require.EqualValues(t, "-- Create \"t1\" table\nCREATE TABLE `t1` (\n `id` int NULL\n);\n", s)
// No changes.
s, err = runCmd(
schemaDiffCmd(),
"--from", openSQLite(t, ""),
"--to", openSQLite(t, ""),
)
require.NoError(t, err)
require.EqualValues(t, "Schemas are synced, no changes to be made.\n", s)
// Format no changes.
s, err = runCmd(
schemaDiffCmd(),
"--from", openSQLite(t, ""),
"--to", openSQLite(t, ""),
"--format", `{{ sql . " " }}`,
)
require.NoError(t, err)
require.Empty(t, s)
// Desired state from migration directory requires dev database.
_, err = runCmd(
schemaDiffCmd(),
"--from", "file://testdata/sqlite",
"--to", openSQLite(t, ""),
)
require.EqualError(t, err, "--dev-url cannot be empty. See: https://atlasgo.io/atlas-schema/sql#dev-database")
// Desired state from migration directory.
s, err = runCmd(
schemaDiffCmd(),
"--from", openSQLite(t, ""),
"--to", "file://testdata/sqlite",
"--dev-url", openSQLite(t, ""),
)
require.NoError(t, err)
require.EqualValues(t, "-- Create \"tbl\" table\nCREATE TABLE `tbl` (`col` int NOT NULL, `col_2` bigint NULL);\n", s)
// Desired state from migration directory.
s, err = runCmd(
schemaDiffCmd(),
"--from", openSQLite(t, ""),
"--to", "file://testdata/sqlite",
"--dev-url", openSQLite(t, ""),
)
require.NoError(t, err)
require.EqualValues(t, "-- Create \"tbl\" table\nCREATE TABLE `tbl` (`col` int NOT NULL, `col_2` bigint NULL);\n", s)
// Current state from migration directory, desired state from HCL - synced.
p := filepath.Join(t.TempDir(), "schema.hcl")
require.NoError(t, os.WriteFile(p, []byte(`schema "main" {}
table "tbl" {
schema = schema.main
column "col" {
type = int
}
column "col_2" {
type = bigint
null = true
}
}`), 0644))
s, err = runCmd(
schemaDiffCmd(),
"--from", "file://testdata/sqlite",
"--to", "file://"+p,
"--dev-url", openSQLite(t, ""),
)
require.NoError(t, err)
require.EqualValues(t, "Schemas are synced, no changes to be made.\n", s)
// Current state from migration directory, desired state from HCL - missing column.
p = filepath.Join(t.TempDir(), "schema.hcl")
require.NoError(t, os.WriteFile(p, []byte(`schema "main" {}
table "tbl" {
schema = schema.main
column "col" {
type = int
}
column "col_2" {
type = bigint
null = true
}
column "col_3" {
type = text
}
}`), 0644))
s, err = runCmd(
schemaDiffCmd(),
"--from", "file://testdata/sqlite",
"--to", "file://"+p,
"--dev-url", openSQLite(t, ""),
)
require.NoError(t, err)
require.EqualValues(
t,
"-- Add column \"col_3\" to table: \"tbl\"\nALTER TABLE `tbl` ADD COLUMN `col_3` text NOT NULL;\n",
s,
)
// Current state from migration directory with version, desired state from HCL - two missing columns.
s, err = runCmd(
schemaDiffCmd(),
"--from", "file://testdata/sqlite?version=20220318104614",
"--to", "file://"+p,
"--dev-url", openSQLite(t, ""),
)
require.NoError(t, err)
require.EqualValues(
t,
"-- Add column \"col_2\" to table: \"tbl\"\n"+
"ALTER TABLE `tbl` ADD COLUMN `col_2` bigint NULL;\n"+
"-- Add column \"col_3\" to table: \"tbl\"\n"+
"ALTER TABLE `tbl` ADD COLUMN `col_3` text NOT NULL;\n",
s,
)
// Current state from migration directory, desired state from multi file HCL - missing column.
p = t.TempDir()
var (
one = filepath.Join(p, "one.hcl")
two = filepath.Join(p, "two.hcl")
)
require.NoError(t, os.WriteFile(one, []byte(`table "tbl" {
schema = schema.main
column "col" {
type = int
}
column "col_2" {
type = bigint
null = true
}
column "col_3" {
type = text
}
}`), 0644))
require.NoError(t, os.WriteFile(two, []byte(`schema "main" {}`), 0644))
s, err = runCmd(
schemaDiffCmd(),
"--from", "file://testdata/sqlite",
"--to", "file://"+p,
"--dev-url", openSQLite(t, ""),
)
require.NoError(t, err)
require.EqualValues(
t,
"-- Add column \"col_3\" to table: \"tbl\"\nALTER TABLE `tbl` ADD COLUMN `col_3` text NOT NULL;\n",
s,
)
s, err = runCmd(
schemaDiffCmd(),
"--from", "file://testdata/sqlite",
"--to", "file://"+one,
"--to", "file://"+two,
"--dev-url", openSQLite(t, ""),
)
require.NoError(t, err)
require.EqualValues(
t,
"-- Add column \"col_3\" to table: \"tbl\"\nALTER TABLE `tbl` ADD COLUMN `col_3` text NOT NULL;\n",
s,
)
t.Run("FromConfig", func(t *testing.T) {
var (
p = t.TempDir()
cp = filepath.Join(p, "atlas.hcl")
sp = filepath.Join(p, "schema.hcl")
cfg = fmt.Sprintf(`
env "local" {
dev = "%s"
format {
schema {
diff = "{{ sql . \"\t\" }}"
}
}
}`, openSQLite(t, ""))
)
require.NoError(t, os.WriteFile(cp, []byte(cfg), 0600))
require.NoError(t, os.WriteFile(sp, []byte(`
schema "main" {}
table "users" {
schema = schema.main
column "id" {
type = int
}
}
`), 0600))
cmd := schemaCmd()
cmd.AddCommand(schemaDiffCmd())
s, err := runCmd(
cmd, "diff",
"-c", "file://"+cp,
"--env", "local",
"--to", "file://"+sp,
"--from", openSQLite(t, ""),
)
require.NoError(t, err)
require.Equal(t, "-- Create \"users\" table\nCREATE TABLE `users` (\n\t`id` int NOT NULL\n);\n", s)
})
t.Run("SkipChanges", func(t *testing.T) {
var (
p = t.TempDir()
cfg = filepath.Join(p, "atlas.hcl")
)
err = os.WriteFile(cfg, []byte(`
variable "destructive" {
type = bool
default = false
}
env "local" {
diff {
skip {
drop_table = !var.destructive
}
}
}
`), 0600)
require.NoError(t, err)
// Skip destructive changes.
cmd := schemaCmd()
cmd.AddCommand(schemaDiffCmd())
s, err := runCmd(
cmd, "diff",
"-c", "file://"+cfg,
"--from", openSQLite(t, "create table users (id int);"),
"--to", openSQLite(t, ""),
"--env", "local",
)
require.NoError(t, err)
require.Equal(t, "Schemas are synced, no changes to be made.\n", s)
// Apply destructive changes.
cmd = schemaCmd()
cmd.AddCommand(schemaDiffCmd())
s, err = runCmd(
cmd, "diff",
"-c", "file://"+cfg,
"--from", openSQLite(t, "create table users (id int);"),
"--to", openSQLite(t, ""),
"--env", "local",
"--var", "destructive=true",
)
require.NoError(t, err)
lines := strings.Split(strings.TrimSpace(s), "\n")
require.Equal(t, []string{
"-- Disable the enforcement of foreign-keys constraints",
"PRAGMA foreign_keys = off;",
`-- Drop "users" table`,
"DROP TABLE `users`;",
"-- Enable back the enforcement of foreign-keys constraints",
"PRAGMA foreign_keys = on;",
}, lines)
})
t.Run("FromConfig/DevURL", func(t *testing.T) {
var (
p = t.TempDir()
cfg = filepath.Join(p, "atlas.hcl")
from = filepath.Join(p, "schema1.sql")
)
err = os.WriteFile(cfg, []byte(`
env "local" {
dev = "sqlite://dev?mode=memory&_fk=1"
exclude = ["posts"]
}
`), 0600)
require.NoError(t, err)
require.NoError(t, os.WriteFile(from, []byte(`CREATE TABLE users (id int);`), 0600))
cmd := schemaCmd()
cmd.AddCommand(schemaDiffCmd())
s, err := runCmd(
cmd, "diff",
"--from", "file://"+from,
"--to", openSQLite(t, "CREATE TABLE users (id int, name text); CREATE TABLE posts (id int);"),
"--config", "file://"+cfg,
"--env", "local",
)
require.NoError(t, err)
require.Equal(t, "-- Add column \"name\" to table: \"users\"\nALTER TABLE `users` ADD COLUMN `name` text NULL;\n", s)
})
t.Run("CompareDataSrc", func(t *testing.T) {
var (
p = t.TempDir()
cfg = filepath.Join(p, "atlas.hcl")
from, to = filepath.Join(p, "schema_from.hcl"), filepath.Join(p, "schema_to.hcl")
)
err = os.WriteFile(cfg, []byte(`
variable "from_path" {
type = string
}
variable "to_path" {
type = string
}
data "hcl_schema" "from" {
path = var.from_path
}
data "hcl_schema" "to" {
path = var.to_path
}
env "drift" {
dev = "sqlite://dev?mode=memory&_fk=1"
# Variables defined and available with env:// prefix.
from_schema = data.hcl_schema.from.url
to_schema = data.hcl_schema.to.url
}
`), 0600)
require.NoError(t, err)
require.NoError(t, os.WriteFile(from, []byte(`
schema "main" {}
table "t1" {
schema = schema.main
column "id" {
type = int
}
}`), 0600))
require.NoError(t, os.WriteFile(to, []byte(`
schema "main" {}
table "t2" {
schema = schema.main
column "id" {
type = int
}
}`), 0600))
cmd := schemaCmd()
cmd.AddCommand(schemaDiffCmd())
s, err := runCmd(
cmd, "diff",
"--config", "file://"+cfg,
"--env", "drift",
"--var", "from_path="+from,
"--var", "to_path="+to,
"--from", "env://from_schema",
"--to", "env://to_schema",
)
require.NoError(t, err)
require.Equal(t, []string{
"-- Disable the enforcement of foreign-keys constraints",
"PRAGMA foreign_keys = off;",
`-- Drop "t1" table`,
"DROP TABLE `t1`;",
`-- Create "t2" table`,
"CREATE TABLE `t2` (`id` int NOT NULL);",
"-- Enable back the enforcement of foreign-keys constraints",
"PRAGMA foreign_keys = on;",
}, strings.Split(strings.TrimSpace(s), "\n"))
})
t.Run("InspectDataSrc", func(t *testing.T) {
var (
p = t.TempDir()
cfg = filepath.Join(p, "atlas.hcl")
app = filepath.Join(p, "schema.hcl")
)
err = os.WriteFile(cfg, []byte(`
variable "path" {
type = string
}
data "hcl_schema" "app" {
path = var.path
}
env "app" {
dev = "sqlite://dev?mode=memory&_fk=1"
# Variables defined and available with env:// prefix.
app = data.hcl_schema.app.url
}
`), 0600)
require.NoError(t, err)
require.NoError(t, os.WriteFile(app, []byte(`
schema "main" {}
table "t1" {
schema = schema.main
column "id" {
type = int
}
}`), 0600))
cmd := schemaCmd()
cmd.AddCommand(schemaInspectCmd())
s, err := runCmd(
cmd, "inspect",
"--config", "file://"+cfg,
"--env", "app",
"--var", "path="+app,
"--url", "env://app",
)
require.NoError(t, err)
require.Equal(t, `table "t1" {
schema = schema.main
column "id" {
null = false
type = int
}
}
schema "main" {
}
`, s)
})
}
func TestSchema_Apply(t *testing.T) {
const drvName = "checknormalizer"
// If no dev-database is given, there must not be a call to Driver.Normalize.
sqlclient.Register(
drvName,
sqlclient.OpenerFunc(func(ctx context.Context, url *url.URL) (*sqlclient.Client, error) {
url.Scheme = "sqlite"
c, err := sqlclient.OpenURL(ctx, url)
if err != nil {
return nil, err
}
c.Driver = &assertNormalizerDriver{t: t, Driver: c.Driver}
return c, nil
}),
)
p := filepath.Join(t.TempDir(), "schema.hcl")
require.NoError(t, os.WriteFile(p, []byte(`schema "my_schema" {}`), 0644))
_, _ = runCmd(
schemaApplyCmd(),
"--url", drvName+"://?mode=memory",
"-f", p,
)
}
func TestSchema_ApplyLog(t *testing.T) {
t.Run("DryRun", func(t *testing.T) {
db := openSQLite(t, "")
cmd := schemaCmd()
cmd.AddCommand(schemaApplyCmd())
s, err := runCmd(
cmd, "apply",
"-u", db,
"--to", openSQLite(t, ""),
"--dry-run",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(t, "{}", s)
cmd = schemaCmd()
cmd.AddCommand(schemaApplyCmd())
s, err = runCmd(
cmd, "apply",
"-u", db,
"--to", openSQLite(t, "create table t1 (id int);"),
"--dry-run",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(
t, "{\"Pending\":[\"CREATE TABLE `t1` (\\n `id` int NULL\\n)\"]}",
strings.ReplaceAll(s, ";", ""), // Compatibility between ent/oss.
)
})
t.Run("AutoApprove", func(t *testing.T) {
db := openSQLite(t, "")
cmd := schemaCmd()
cmd.AddCommand(schemaApplyCmd())
s, err := runCmd(
cmd, "apply",
"-u", db,
"--to", openSQLite(t, "create table t1 (id int);"),
"--auto-approve",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(
t, "{\"Applied\":[\"CREATE TABLE `t1` (\\n `id` int NULL\\n)\"]}",
strings.ReplaceAll(s, ";", ""), // Compatibility between ent/oss.
)
cmd = schemaCmd()
cmd.AddCommand(schemaApplyCmd())
s, err = runCmd(
cmd, "apply",
"-u", db,
"--to", openSQLite(t, "create table t1 (id int);"),
"--auto-approve",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(t, "{}", s)
cmd = schemaCmd()
cmd.AddCommand(schemaApplyCmd())
s, err = runCmd(
cmd, "apply",
"-u", db,
"--to", openSQLite(t, "create table t2 (id int);"),
"--auto-approve",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(
t, "{\"Applied\":[\"PRAGMA foreign_keys = off\",\"DROP TABLE `t1`\",\"CREATE TABLE `t2` (\\n `id` int NULL\\n)\",\"PRAGMA foreign_keys = on\"]}",
strings.ReplaceAll(s, ";", ""), // Compatibility between ent/oss.
)
// Simulate a failed execution.
conn, err := sql.Open("sqlite3", strings.TrimPrefix(db, "sqlite://"))
require.NoError(t, err)
_, err = conn.Exec("INSERT INTO t2 (`id`) VALUES (1), (1)")
require.NoError(t, err)
cmd = schemaCmd()
cmd.AddCommand(schemaApplyCmd())
s, err = runCmd(
cmd, "apply",
"-u", db,
"--to", openSQLite(t, "create table t2 (id int, c int);create unique index t2_id on t2 (id);"),
"--auto-approve",
"--format", "{{ json .Changes }}\n",
)
require.ErrorContains(t, err, `UNIQUE constraint failed: t2.id`)
var out struct {
Applied []string
Pending []string
Error cmdlog.StmtError
}
require.NoError(t, json.NewDecoder(strings.NewReader(s)).Decode(&out))
require.Len(t, out.Applied, 1)
require.Len(t, out.Pending, 1)
require.Equal(t, "ALTER TABLE `t2` ADD COLUMN `c` int NULL", strings.TrimRight(out.Applied[0], ";"))
require.Equal(t, "CREATE UNIQUE INDEX `t2_id` ON `t2` (`id`)", strings.TrimRight(out.Pending[0], ";"))
require.Equal(t, out.Pending[0], out.Error.Stmt)
require.Contains(t, out.Error.Text, `UNIQUE constraint failed: t2.id`)
})
}
func TestSchema_ApplySchemaMismatch(t *testing.T) {
var (
p = t.TempDir()
src = filepath.Join(p, "schema.hcl")
)
// SQLite always has a schema called "main".
err := os.WriteFile(src, []byte(`
schema "hello" {}
`), 0600)
require.NoError(t, err)
cmd := schemaCmd()
cmd.AddCommand(schemaApplyCmd())
_, err = runCmd(
cmd, "apply",
"-u", openSQLite(t, ""),
"-f", src,
)
require.EqualError(t, err, `mismatched HCL and database schemas: "main" <> "hello"`)
}
func TestSchema_ApplySkip(t *testing.T) {
var (
p = t.TempDir()
cfg = filepath.Join(p, "atlas.hcl")
src = filepath.Join(p, "schema.hcl")
)
err := os.WriteFile(src, []byte(`
schema "main" {}
table "users" {
schema = schema.main
column "id" {
type = int
}
}
`), 0600)
require.NoError(t, err)
err = os.WriteFile(cfg, []byte(`
variable "schema" {
type = string
default = "dev"
}
variable "destructive" {
type = bool
default = false
}
env "local" {
src = var.schema
dev_url = "sqlite://dev?mode=memory&_fk=1"
}
diff {
skip {
drop_table = !var.destructive
}
}
`), 0600)
require.NoError(t, err)
// Skip destructive changes.
cmd := schemaCmd()
cmd.AddCommand(schemaApplyCmd())
s, err := runCmd(
cmd, "apply",
"-u", openSQLite(t, "create table pets (id int);"),
"-c", "file://"+cfg,
"--var", "schema=file://"+src,
"--env", "local",
"--auto-approve",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(
t, "{\"Applied\":[\"CREATE TABLE `users` (\\n `id` int NOT NULL\\n)\"]}",
strings.ReplaceAll(s, ";", ""), // Compatibility between ent/oss.
)
// Skip destructive changes by using project-level policy (no --env was passed).
cmd = schemaCmd()
cmd.AddCommand(schemaApplyCmd())
s, err = runCmd(
cmd, "apply",
"-u", openSQLite(t, "create table pets (id int);"),
"-c", "file://"+cfg, // Using the project-level policy.
"--to", "file://"+src,
"--dev-url", "sqlite://dev?mode=memory&_fk=1",
"--auto-approve",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(
t, "{\"Applied\":[\"CREATE TABLE `users` (\\n `id` int NOT NULL\\n)\"]}",
strings.ReplaceAll(s, ";", ""), // Compatibility between ent/oss.
)
// Apply destructive changes.
cmd = schemaCmd()
cmd.AddCommand(schemaApplyCmd())
s, err = runCmd(
cmd, "apply",
"-u", openSQLite(t, "create table pets (id int);"),
"-c", "file://"+cfg,
"--var", "schema=file://"+src,
"--var", "destructive=true",
"--env", "local",
"--auto-approve",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(
t, "{\"Applied\":[\"PRAGMA foreign_keys = off\",\"DROP TABLE `pets`\",\"CREATE TABLE `users` (\\n `id` int NOT NULL\\n)\",\"PRAGMA foreign_keys = on\"]}",
strings.ReplaceAll(s, ";", ""), // Compatibility between ent/oss.
)
}
func TestSchema_ApplySources(t *testing.T) {
var (
p = t.TempDir()
cfg = filepath.Join(p, "atlas.hcl")
src = []string{filepath.Join(p, "one.hcl"), filepath.Join(p, "two.hcl")}
)
err := os.WriteFile(src[0], []byte(`
schema "main" {}
table "one" {
schema = schema.main
column "id" {
type = int
}
}
`), 0600)
require.NoError(t, err)
err = os.WriteFile(src[1], []byte(`
table "two" {
schema = schema.main
column "id" {
type = int
}
}
`), 0600)
require.NoError(t, err)
err = os.WriteFile(cfg, []byte(fmt.Sprintf(`
env "local" {
src = [%q, %q]
}`, src[0], src[1])), 0600)
require.NoError(t, err)
cmd := schemaCmd()
cmd.AddCommand(schemaApplyCmd())
s, err := runCmd(
cmd, "apply",
"-u", openSQLite(t, ""),
"-c", "file://"+cfg,
"--env", "local",
"--auto-approve",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(
t, "{\"Applied\":[\"CREATE TABLE `one` (\\n `id` int NOT NULL\\n)\",\"CREATE TABLE `two` (\\n `id` int NOT NULL\\n)\"]}",
strings.ReplaceAll(s, ";", ""), // Compatibility between ent/oss.
)
}
func TestSchema_ToFlagPrecedence(t *testing.T) {
var (
p = t.TempDir()
cfg = filepath.Join(p, "atlas.hcl")
hclFile = filepath.Join(p, "schema.hcl")
sqlFile = filepath.Join(p, "schema.sql")
)
err := os.WriteFile(hclFile, []byte(`
schema "main" {}
table "one" {
schema = schema.main
column "id" {
type = int
}
}
`), 0600)
require.NoError(t, err)
err = os.WriteFile(sqlFile, []byte("create table tbl (col integer)"), 0600)
require.NoError(t, err)
err = os.WriteFile(cfg, []byte(fmt.Sprintf(`
env "local" {
src = "file://%s"
}`, sqlFile)), 0600)
require.NoError(t, err)
cmd := schemaCmd()
cmd.AddCommand(schemaApplyCmd())
s, err := runCmd(
cmd, "apply",
"-u", openSQLite(t, ""),
"-c", "file://"+cfg,
"--to", "file://"+hclFile,
"--env", "local",
"--auto-approve",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(
t, "{\"Applied\":[\"CREATE TABLE `one` (\\n `id` int NOT NULL\\n)\"]}",
strings.ReplaceAll(s, ";", ""), // Compatibility between ent/oss.
)
}
func TestSchema_ApplySQL(t *testing.T) {
t.Run("File", func(t *testing.T) {
db := openSQLite(t, "")
p := filepath.Join(t.TempDir(), "schema.sql")
require.NoError(t, os.WriteFile(p, []byte(`create table t1 (id int NOT NULL);`), 0600))
s, err := runCmd(
schemaApplyCmd(),
"-u", db,
"--dev-url", openSQLite(t, ""),
"--to", "file://"+p,
"--auto-approve",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(
t, "{\"Applied\":[\"CREATE TABLE `t1` (\\n `id` int NOT NULL\\n)\"]}",
strings.ReplaceAll(s, ";", ""), // Compatibility between ent/oss.
)
s, err = runCmd(
schemaApplyCmd(),
"-u", db,
"--dev-url", openSQLite(t, ""),
"--to", "file://"+p,
"--auto-approve",
)
require.NoError(t, err)
require.Equal(t, "Schema is synced, no changes to be made\n", s)
})
t.Run("Dir", func(t *testing.T) {
db := openSQLite(t, "")
s, err := runCmd(
schemaApplyCmd(),
"-u", db,
"--dev-url", openSQLite(t, ""),
"--to", "file://testdata/sqlite",
"--auto-approve",
"--format", "{{ json .Changes }}",
)
require.NoError(t, err)
require.Equal(
t, "{\"Applied\":[\"CREATE TABLE `tbl` (\\n `col` int NOT NULL,\\n `col_2` bigint NULL\\n)\"]}",
strings.ReplaceAll(s, ";", ""), // Compatibility between ent/oss.
)
s, err = runCmd(
schemaApplyCmd(),
"-u", db,
"--dev-url", openSQLite(t, ""),
"--to", "file://testdata/sqlite",
"--auto-approve",
)
require.NoError(t, err)
require.Equal(t, "Schema is synced, no changes to be made\n", s)
})
t.Run("Error", func(t *testing.T) {
_, err := runCmd(
schemaApplyCmd(),
"-u", openSQLite(t, ""),
"--dev-url", openSQLite(t, ""),
"--to", "file://testdata/sqlite",
"--to", "file://testdata/sqlite2",
)
require.Error(t, err)
_, err = runCmd(
schemaApplyCmd(),
"-u", openSQLite(t, ""),
"--dev-url", openSQLite(t, ""),
"--to", "file://"+t.TempDir(),
)
require.ErrorContains(t, err, `contains neither SQL nor HCL files`)
p := t.TempDir()
require.NoError(t, os.WriteFile(filepath.Join(p, "schema.sql"), []byte(`create table t1 (id int NOT NULL);`), 0600))
require.NoError(t, os.WriteFile(filepath.Join(p, "schema.hcl"), []byte(`schema "main" {}`), 0600))
_, err = runCmd(
schemaApplyCmd(),
"-u", openSQLite(t, ""),
"--dev-url", openSQLite(t, ""),
"--to", "file://"+p,
)
require.EqualError(t, err, `ambiguous schema: both SQL and HCL files found: "schema.hcl", "schema.sql"`)
_, err = runCmd(
schemaApplyCmd(),
"-u", openSQLite(t, ""),
"--dev-url", openSQLite(t, ""),
"--to", "testdata/sqlite",
)
require.EqualError(t, err, "missing scheme. Did you mean file://testdata/sqlite?")
})
t.Run("TxMode", func(t *testing.T) {
db := openSQLite(t, "")
p := filepath.Join(t.TempDir(), "schema.hcl")
require.NoError(t, os.WriteFile(p, []byte(`schema "main" {}
table "ok" {
schema = schema.main
column "id" {
type = int
}
}
table "bad" {
schema = schema.main
column "id" {
type = int
default = "invalid check"
}
}`), 0600))
s, err := runCmd(
schemaApplyCmd(),
"-u", db,
"--to", "file://"+p,
"--auto-approve",
"--format", "{{ json .Changes }}",
)
require.Error(t, err)
require.Contains(
t, strings.ReplaceAll(s, ";", ""), // Compatibility between ent/oss.
"{\"Applied\":[\"CREATE TABLE `ok` (\\n `id` int NOT NULL\\n)\"],\"Pending\":[\"CREATE TABLE `bad` (\\n `id` int NOT NULL DEFAULT invalid check\\n)\"],\"Error\":{\"Stmt\":\"CREATE TABLE `bad` (\\n `id` int NOT NULL DEFAULT invalid check\\n)\",",
)
require.Regexp(t, `Error: .* near "\)": syntax error`, s)
// The "ok" table should be created, as changes are rolled back on error.
s, err = runCmd(schemaInspectCmd(), "-u", db)
require.NoError(t, err)
require.Equal(t, "schema \"main\" {\n}\n", s)
})
}
func TestSchema_ApplyReview(t *testing.T) {
t.Run("mutex-auto-approve", func(t *testing.T) {
cfg := filepath.Join(t.TempDir(), "atlas.hcl")
require.NoError(t, os.WriteFile(cfg, []byte(`env "test" {
lint {
review = WARNING
}
}`), 0600))
db := openSQLite(t, "")
p := filepath.Join(t.TempDir(), "schema.sql")
require.NoError(t, os.WriteFile(p, []byte(`create table t1 (id int NOT NULL);`), 0600))
cmd := schemaCmd()
cmd.AddCommand(schemaApplyCmd())
_, err := runCmd(
cmd,
"apply",
"-c", "file://"+cfg,
"--url", db,
"--env", "test",
"--dev-url", openSQLite(t, ""),
"--to", "file://"+p,
"--auto-approve",
)
require.ErrorContains(t, err, `auto-approve is not allowed when a lint policy is set to "WARNING"`)
})
}
func TestSchema_InspectLog(t *testing.T) {
db := openSQLite(t, "create table t1 (id integer primary key);create table t2 (name text);")
cmd := schemaCmd()
cmd.AddCommand(schemaInspectCmd())
s, err := runCmd(
cmd, "inspect",
"-u", db,
"--format", "{{ json . }}",
)
require.NoError(t, err)
require.Equal(t, `{"schemas":[{"name":"main","tables":[{"name":"t1","columns":[{"name":"id","type":"INTEGER","null":true}],"primary_key":{"parts":[{"column":"id"}]}},{"name":"t2","columns":[{"name":"name","type":"TEXT","null":true}]}]}]}`, s)
}
func TestSchema_InspectFile(t *testing.T) {
var (
p = t.TempDir()
cp = filepath.Join(p, "atlas.hcl")
sp = filepath.Join(p, "schema.hcl")
cfg = fmt.Sprintf(`
env "db" {
url = "%s"
dev = "docker://should-not-be-opened"
}
env "file" {
dev = "%s"
}
`, openSQLite(t, "create table t1(c int)"), openSQLite(t, ""))
)
require.NoError(t, os.WriteFile(cp, []byte(cfg), 0600))
require.NoError(t, os.WriteFile(sp, []byte(`
schema "main" {}
table "users" {
schema = schema.main
column "id" {
type = int
}
}
`), 0600))
cmd := schemaCmd()
cmd.AddCommand(schemaInspectCmd())
s, err := runCmd(
cmd, "inspect",
"-c", "file://"+cp,
"--env", "db",
"--format", "{{ sql . }}",
)
require.NoError(t, err)
require.Equal(t, "-- Create \"t1\" table\nCREATE TABLE `t1` (`c` int NULL);\n", s)
cmd = schemaCmd()
cmd.AddCommand(schemaInspectCmd())
s, err = runCmd(
cmd, "inspect",
"-c", "file://"+cp,
"--env", "file",
"--url", "file://"+sp,
"--format", "{{ sql . }}",
)
require.NoError(t, err)
require.Equal(t, "-- Create \"users\" table\nCREATE TABLE `users` (`id` int NOT NULL);\n", s)
}
func TestFmt(t *testing.T) {
for _, tt := range []struct {
name string
inputDir map[string]string
expectedDir map[string]string
expectedFile string
expectedOut string
args []string
expectedPrint bool
}{
{
name: "specific file",
inputDir: map[string]string{
"test.hcl": unformatted,
},
expectedDir: map[string]string{
"test.hcl": formatted,
},
args: []string{"test.hcl"},
expectedOut: "test.hcl\n",
},
{
name: "current dir",
inputDir: map[string]string{
"test.hcl": unformatted,
},
expectedDir: map[string]string{
"test.hcl": formatted,
},
expectedOut: "test.hcl\n",
},
{
name: "multi path implicit",
inputDir: map[string]string{
"test.hcl": unformatted,
"test2.hcl": unformatted,
},
expectedDir: map[string]string{
"test.hcl": formatted,
"test2.hcl": formatted,
},
expectedOut: "test.hcl\ntest2.hcl\n",
},
{
name: "multi path explicit",
inputDir: map[string]string{
"test.hcl": unformatted,
"test2.hcl": unformatted,
},
expectedDir: map[string]string{
"test.hcl": formatted,
"test2.hcl": formatted,
},
args: []string{"test.hcl", "test2.hcl"},
expectedOut: "test.hcl\ntest2.hcl\n",
},
{
name: "formatted",
inputDir: map[string]string{
"test.hcl": formatted,
},
expectedDir: map[string]string{
"test.hcl": formatted,
},
},
} {
t.Run(tt.name, func(t *testing.T) {
dir := setupFmtTest(t, tt.inputDir)
out, err := runCmd(schemaFmtCmd(), tt.args...)
require.NoError(t, err)
assertDir(t, dir, tt.expectedDir)
require.EqualValues(t, tt.expectedOut, out)
})
}
}
func TestSchema_Clean(t *testing.T) {
var (
u = fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(t.TempDir(), "test.db"))
c, err = sqlclient.Open(context.Background(), u)
)
require.NoError(t, err)
// Apply migrations onto database.
_, err = runCmd(migrateApplyCmd(), "--dir", "file://testdata/sqlite", "--url", u)
require.NoError(t, err)
// Run clean and expect to be clean.
_, err = runCmd(migrateApplyCmd(), "--dir", "file://testdata/sqlite", "--url", u)
require.NoError(t, err)
s, err := runCmd(schemaCleanCmd(), "--url", u, "--auto-approve")
require.NoError(t, err)
require.NotZero(t, s)
require.NoError(t, c.Driver.CheckClean(context.Background(), nil))
}
func assertDir(t *testing.T, dir string, expected map[string]string) {
act := make(map[string]string)
files, err := os.ReadDir(dir)
require.NoError(t, err)
for _, f := range files {
if f.IsDir() {
continue
}
contents, err := os.ReadFile(filepath.Join(dir, f.Name()))
require.NoError(t, err)
act[f.Name()] = string(contents)
}
require.EqualValues(t, expected, act)
}
func setupFmtTest(t *testing.T, inputDir map[string]string) string {
wd, err := os.Getwd()
require.NoError(t, err)
dir, err := os.MkdirTemp(os.TempDir(), "fmt-test-")
require.NoError(t, err)
err = os.Chdir(dir)
require.NoError(t, err)
t.Cleanup(func() {
os.RemoveAll(dir)
os.Chdir(wd) //nolint:errcheck
})
for name, contents := range inputDir {
file := path.Join(dir, name)
err = os.WriteFile(file, []byte(contents), 0600)
}
require.NoError(t, err)
return dir
}
type assertNormalizerDriver struct {
migrate.Driver
t *testing.T
}
// NormalizeSchema returns the normal representation of a schema.
func (d *assertNormalizerDriver) NormalizeSchema(context.Context, *schema.Schema) (*schema.Schema, error) {
d.t.Fatal("did not expect a call to NormalizeSchema")
return nil, nil
}
// NormalizeRealm returns the normal representation of a database.
func (d *assertNormalizerDriver) NormalizeRealm(context.Context, *schema.Realm) (*schema.Realm, error) {
d.t.Fatal("did not expect a call to NormalizeRealm")
return nil, nil
}
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/baseline1/1_baseline.sql
================================================
-- create "baseline" table
CREATE TABLE baseline (`c` int NOT NULL);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/baseline1/atlas.sum
================================================
h1:GqOjMVGk2H0qYhhtJ1SPCyyHEBbWP/LD2ueWQTY4e6A=
1_baseline.sql h1:rZgkRmNcN2UEKgxru1nHCpBRVn/fjFavyQ4xxPxhrD4=
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/baseline2/1_baseline.sql
================================================
-- create "baseline" table
CREATE TABLE baseline (`c` int NOT NULL);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/baseline2/20220318104614_initial.sql
================================================
-- create "tbl" table
CREATE TABLE tbl (`col` int NOT NULL);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/baseline2/20220318104615_second.sql
================================================
ALTER TABLE `tbl` ADD `col_2` bigint;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/baseline2/atlas.sum
================================================
h1:sxNQqhuqhm1fLpr3WN9N/M/niaS81Y7k5RrSaKpmBZE=
1_baseline.sql h1:rZgkRmNcN2UEKgxru1nHCpBRVn/fjFavyQ4xxPxhrD4=
20220318104614_initial.sql h1:/B1/+IxzgrRc4tCm1tpcpMhocHgqkdWF+iffxuguYaQ=
20220318104615_second.sql h1:nUc1cUvm8BzjTZdbavM1IRlNpfhtyY3YyZJ8v23K9j4=
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/dbmate/1_initial.sql
================================================
-- migrate:up
CREATE TABLE post
(
id int NOT NULL,
title text,
body text,
PRIMARY KEY (id)
);
/*
Multiline comment ...
*/
ALTER TABLE post ADD created_at TIMESTAMP NOT NULL;
-- Normal comment
-- With a second line
INSERT INTO post (title) VALUES (
'This is
my multiline
value');
-- migrate:down
DROP TABLE post;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/dbmate/2_second_migration.sql
================================================
-- migrate:up
CREATE TABLE tbl_2 (col INT);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/dbmate_gold/1_initial.sql
================================================
CREATE TABLE post
(
id int NOT NULL,
title text,
body text,
PRIMARY KEY (id)
);
/*
Multiline comment ...
*/
ALTER TABLE post ADD created_at TIMESTAMP NOT NULL;
-- Normal comment
-- With a second line
INSERT INTO post (title) VALUES (
'This is
my multiline
value');
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/dbmate_gold/2_second_migration.sql
================================================
CREATE TABLE tbl_2 (col INT);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/flyway/B2__baseline.sql
================================================
CREATE TABLE post
(
id int NOT NULL,
title text,
body text,
created_at TIMESTAMP NOT NULL
PRIMARY KEY (id)
);
INSERT INTO post (title, created_at) VALUES (
'This is
my multiline
value', NOW());
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/flyway/R__views.sql
================================================
CREATE VIEW `my_view` AS SELECT * FROM `post`;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/flyway/U1__initial.sql
================================================
DROP TABLE tbl;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/flyway/V1__initial.sql
================================================
-- comment
CREATE TABLE post
(
id int NOT NULL,
title text,
body text,
PRIMARY KEY (id)
);
ALTER TABLE post ADD created_at TIMESTAMP NOT NULL;
INSERT INTO post (title, created_at) VALUES (
'This is
my multiline
value', NOW());
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/flyway/V2__second_migration.sql
================================================
-- migrate:up
CREATE TABLE tbl_2 (col INT);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/flyway/V3__third_migration.sql
================================================
ALTER TABLE tbl_2 ADD col_1 INTEGER NOT NULL;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/flyway_gold/2_baseline.sql
================================================
CREATE TABLE post
(
id int NOT NULL,
title text,
body text,
created_at TIMESTAMP NOT NULL
PRIMARY KEY (id)
);
INSERT INTO post (title, created_at) VALUES (
'This is
my multiline
value', NOW());
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/flyway_gold/3R_views.sql
================================================
CREATE VIEW `my_view` AS SELECT * FROM `post`;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/flyway_gold/3_third_migration.sql
================================================
ALTER TABLE tbl_2 ADD col_1 INTEGER NOT NULL;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/golang-migrate/1_initial.down.sql
================================================
DROP TABLE tbl;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/golang-migrate/1_initial.up.sql
================================================
CREATE TABLE tbl
(
col INT
);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/golang-migrate/2_second_migration.down.sql
================================================
DROP TABLE tbl_2;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/golang-migrate/2_second_migration.up.sql
================================================
CREATE TABLE tbl_2 (col INT);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/golang-migrate_gold/1_initial.sql
================================================
CREATE TABLE tbl
(
col INT
);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/golang-migrate_gold/2_second_migration.sql
================================================
CREATE TABLE tbl_2 (col INT);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/goose/1_initial.sql
================================================
-- +goose Up
CREATE TABLE post
(
id int NOT NULL,
title text,
body text,
PRIMARY KEY (id)
);
ALTER TABLE post ADD created_at TIMESTAMP NOT NULL;
INSERT INTO post (title) VALUES (
'This is
my multiline
value');
-- +goose Down
DROP TABLE post;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/goose/2_second_migration.sql
================================================
-- +goose Up
ALTER TABLE post ADD updated_at TIMESTAMP NOT NULL;
-- +goose StatementBegin
-- Comment for the function declaration.
CREATE
OR REPLACE FUNCTION histories_partition_creation( DATE, DATE )
returns void AS $$
DECLARE
create_query text;
BEGIN
FOR create_query IN
SELECT 'CREATE TABLE IF NOT EXISTS histories_'
|| TO_CHAR(d, 'YYYY_MM')
|| ' ( CHECK( created_at >= timestamp '''
|| TO_CHAR(d, 'YYYY-MM-DD 00:00:00')
|| ''' AND created_at < timestamp '''
|| TO_CHAR(d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00')
|| ''' ) ) inherits ( histories );'
FROM generate_series($1, $2, '1 month') AS d LOOP
EXECUTE create_query;
END LOOP; -- LOOP END
END; -- FUNCTION END
$$
language plpgsql;
-- +goose StatementEnd
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/goose_gold/1_initial.sql
================================================
CREATE TABLE post
(
id int NOT NULL,
title text,
body text,
PRIMARY KEY (id)
);
ALTER TABLE post ADD created_at TIMESTAMP NOT NULL;
INSERT INTO post (title) VALUES (
'This is
my multiline
value');
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/goose_gold/2_second_migration.sql
================================================
ALTER TABLE post ADD updated_at TIMESTAMP NOT NULL;
-- Comment for the function declaration.
CREATE
OR REPLACE FUNCTION histories_partition_creation( DATE, DATE )
returns void AS $$
DECLARE
create_query text;
BEGIN
FOR create_query IN
SELECT 'CREATE TABLE IF NOT EXISTS histories_'
|| TO_CHAR(d, 'YYYY_MM')
|| ' ( CHECK( created_at >= timestamp '''
|| TO_CHAR(d, 'YYYY-MM-DD 00:00:00')
|| ''' AND created_at < timestamp '''
|| TO_CHAR(d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00')
|| ''' ) ) inherits ( histories );'
FROM generate_series($1, $2, '1 month') AS d LOOP
EXECUTE create_query;
END LOOP; -- LOOP END
END; -- FUNCTION END
$$
language plpgsql;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/liquibase/1_initial.sql
================================================
--liquibase formatted sql
--changeset atlas:1-1
CREATE TABLE post
(
id int NOT NULL,
title text,
body text,
PRIMARY KEY (id)
);
--rollback: DROP TABLE post;
--changeset atlas:1-2
ALTER TABLE post ADD created_at TIMESTAMP NOT NULL;
--rollback: ALTER TABLE post DROP created_at;
--changeset atlas:1-3
INSERT INTO post (title) VALUES (
'This is
my multiline
value');
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/liquibase/2_second_migration.sql
================================================
--liquibase formatted sql
--changeset atlas:2-1
CREATE TABLE tbl_2 (col INT);
--rollback DROP TABLE tbl_2;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/liquibase_gold/1_initial.sql
================================================
--changeset atlas:1-1
CREATE TABLE post
(
id int NOT NULL,
title text,
body text,
PRIMARY KEY (id)
);
--changeset atlas:1-2
ALTER TABLE post ADD created_at TIMESTAMP NOT NULL;
--changeset atlas:1-3
INSERT INTO post (title) VALUES (
'This is
my multiline
value');
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/import/liquibase_gold/2_second_migration.sql
================================================
--changeset atlas:2-1
CREATE TABLE tbl_2 (col INT);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/mysql/20220318104614_initial.sql
================================================
-- add new schema named "atlantis"
CREATE DATABASE `atlantis`;
-- create "tbl" table
CREATE TABLE `atlantis`.`tbl` (`col` int NOT NULL) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/mysql/20220420213403_second.sql
================================================
ALTER TABLE `atlantis`.`tbl` ADD `col_2` TEXT;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/mysql/atlas.sum
================================================
h1:EGX5/CEEerpLWqYQNHB1veTXon8t05wEGJiX2fOtFXg=
20220318104614_initial.sql h1:EoDHPlX7fTGn5qiCdR5xhwFh+DrOi3cQ7Y49BsIy97k=
20220420213403_second.sql h1:cAioQjDgJkOIiMAyEwqaurPs0EHpTeu0CnWlJzNj5SE=
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlite/20220318104614_initial.sql
================================================
-- create "tbl" table
CREATE TABLE tbl (`col` int NOT NULL);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlite/20220318104615_second.sql
================================================
ALTER TABLE `tbl` ADD `col_2` bigint;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlite/atlas.sum
================================================
h1:GMi7mvWSIHv0I/Wrc2NCGVt9Z5hWZbPa6wL986t7Z2o=
20220318104614_initial.sql h1:FifWjY2X0g2YVnb18Qm+QBPvoldDOOob7bS0LrFuCXc=
20220318104615_second.sql h1:wbPDlODOQeixCiopAhlT7W4xOO9TgJxzjYjxf4TA2f4=
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlite2/20220318104614_initial.sql
================================================
-- create "tbl" table
CREATE TABLE tbl (`col` int NOT NULL);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlite2/20220318104615_second.sql
================================================
ALTER TABLE `tbl` ADD `col_2` bigint;
asdasd ALTER TABLE `tbl` ADD `col_3` bigint; -- will fail
ALTER TABLE `tbl` ADD `col_4` bigint;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlite2/atlas.sum
================================================
h1:lXdG49p5Vr5b9eARNKq3Gkgd+flbQXDM+XDyB6b2nzw=
20220318104614_initial.sql h1:FifWjY2X0g2YVnb18Qm+QBPvoldDOOob7bS0LrFuCXc=
20220318104615_second.sql h1:UA1TOODS2yU138E2HBlChe/O8vSmTRxkHs4OJOUK3K8=
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx/20220925092817_initial.sql
================================================
-- create "users" table
CREATE TABLE `users` (`id` integer NOT NULL, `name` text NULL, PRIMARY KEY (`id`));
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx/20220925094021_second.sql
================================================
-- create "friendships" table
CREATE TABLE `friendships` (`user_id` integer NOT NULL, `friend_id` integer NOT NULL, PRIMARY KEY (`user_id`, `friend_id`), CONSTRAINT `user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE, CONSTRAINT `friend_id_fk` FOREIGN KEY (`friend_id`) REFERENCES `users` (`id`) ON DELETE CASCADE);
INSERT INTO `users` (`id`) VALUES (1), (2);
INSERT INTO `friendships` (`user_id`, `friend_id`) VALUES (1,2), (2,1);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx/20220925094437_third.sql
================================================
-- disable the enforcement of foreign-keys constraints
PRAGMA foreign_keys = off;
-- create "new_users" table
CREATE TABLE `new_users` (`id` integer NOT NULL, PRIMARY KEY (`id`));
-- copy rows from old table "users" to new temporary table "new_users"
INSERT INTO `new_users` (`id`) SELECT `id` FROM `users`;
-- drop "users" table after copying rows
DROP TABLE `users`;
-- rename temporary table "new_users" to "users"
ALTER TABLE `new_users` RENAME TO `users`;
-- enable back the enforcement of foreign-keys constraints
PRAGMA foreign_keys = on;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx/atlas.sum
================================================
h1:09lkmQGTxdoqPwK0ZXtU4+KHipufkVp1Jlje3t6Opy4=
20220925092817_initial.sql h1:ZGeLdeqNUMXqJm+hPkhBrhzbtUzSBH8yVTsnSnJo/qU=
20220925094021_second.sql h1:vcoquz3yk+TlTPiQgW5hHpS/abIvySCM/bzgwYTDoqY=
20220925094437_third.sql h1:2pbBiUBKsEC5+ppfPPTDr+iwJSgZ2rM4qmHI44/vmnc=
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx2/20220925092817_initial.sql
================================================
-- create "users" table
CREATE TABLE `users` (`id` integer NOT NULL, `name` text NULL, PRIMARY KEY (`id`));
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx2/20220925094021_second.sql
================================================
-- create "friendships" table
CREATE TABLE `friendships` (`user_id` integer NOT NULL, `friend_id` integer NOT NULL, PRIMARY KEY (`user_id`, `friend_id`), CONSTRAINT `user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE, CONSTRAINT `friend_id_fk` FOREIGN KEY (`friend_id`) REFERENCES `users` (`id`) ON DELETE CASCADE);
INSERT INTO `users` (`id`) VALUES (1), (2);
INSERT INTO `friendships` (`user_id`, `friend_id`) VALUES (1,2), (2,1);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx2/20220925094437_third.sql
================================================
-- disable the enforcement of foreign-keys constraints
PRAGMA foreign_keys = off;
-- create "new_users" table
CREATE TABLE `new_users` (`id` integer NOT NULL, PRIMARY KEY (`id`));
-- copy rows from old table "users" to new temporary table "new_users"
INSERT INTO `new_users` (`id`) SELECT `id` FROM `users`;
-- drop "users" table after copying rows
DROP TABLE `users`;
-- rename temporary table "new_users" to "users"
ALTER TABLE `new_users` RENAME TO `users`;
-- insert faulty data
INSERT INTO `friendships` (`user_id`, `friend_id`) VALUES (3,2);
-- enable back the enforcement of foreign-keys constraints
PRAGMA foreign_keys = on;
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx2/atlas.sum
================================================
h1:eH+7c2mVWbrhky00/3SKYklyHLyz+QzDk1UZJ9+ZJsg=
20220925092817_initial.sql h1:ZGeLdeqNUMXqJm+hPkhBrhzbtUzSBH8yVTsnSnJo/qU=
20220925094021_second.sql h1:vcoquz3yk+TlTPiQgW5hHpS/abIvySCM/bzgwYTDoqY=
20220925094437_third.sql h1:58glD96PVBa0fSu8x/3Gbwbf7N6WjAcVl4jh/XcNXoM=
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx3/20220925092817_initial.sql
================================================
-- create "users" table
CREATE TABLE `users` (`id` integer NOT NULL, `name` text NULL, PRIMARY KEY (`id`));
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx3/20220925094021_second.sql
================================================
-- atlas:txmode none
-- Create a table.
CREATE TABLE t1 (a INTEGER PRIMARY KEY);
-- Cause migrations to fail.
INSERT INTO t1 VALUES (1), (1);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx3/atlas.sum
================================================
h1:tTdOsRIKj8kX3o4eUQpw6znQsGVorkUrxi2o3C/ELL4=
20220925092817_initial.sql h1:ZGeLdeqNUMXqJm+hPkhBrhzbtUzSBH8yVTsnSnJo/qU=
20220925094021_second.sql h1:RTw52JCxOkWfSnY1N/kRZeLkmAFmvY2BXfZKDzhV3QM=
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx4/20220925092817_initial.sql
================================================
-- create "users" table
CREATE TABLE `users` (`id` integer NOT NULL, `name` text NULL, PRIMARY KEY (`id`));
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx4/20220925094021_second.sql
================================================
-- atlas:txmode unknown
-- Create a table.
CREATE TABLE t1 (a INTEGER PRIMARY KEY);
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/sqlitetx4/atlas.sum
================================================
h1:RO76A3Kj66lD13e+iIb5lafWPtz4S3ypswaBm5kPRrI=
20220925092817_initial.sql h1:ZGeLdeqNUMXqJm+hPkhBrhzbtUzSBH8yVTsnSnJo/qU=
20220925094021_second.sql h1:MH4JwNo3hLxH0rauBusXr3IvJJFm9EC2TPe0DhXbgkE=
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/templatedir/1.sql
================================================
{{- if eq .Env "dev" }}
create table dev1 (c text);
{{- else }}
create table prod1 (c text);
{{- end }}
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/templatedir/2.sql
================================================
{{- if eq .Env "dev" }}
create table dev2 (c text);
{{ template "shared/users" "dev2" }}
{{- else }}
create table prod2 (c text);
{{ template "shared/users" "prod2" }}
{{- end }}
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/templatedir/atlas.sum
================================================
h1:qhwlEKNEXRVSUiyBXmbiSiS26un12DoxHCR3WDzrDdA=
1.sql h1:b/5P45x6+CVoyVbBJ/BVc5Z2cI46XfoW92QH3T1kqxY=
2.sql h1:El2EOcXWK2PfPV6yJg4hBVtc4aHheV/MFEPjho9SEmQ=
================================================
FILE: cmd/atlas/internal/cmdapi/testdata/templatedir/shared/users.sql
================================================
{{- define "shared/users" }}
create table users_{{ $ }} (c text);
{{- end}}
================================================
FILE: cmd/atlas/internal/cmdapi/vercheck/notification.tmpl
================================================
{{- with .Advisory -}}
SECURITY ADVISORY
{{ .Text }}
{{- end }}
{{- with .Latest -}}
A new version of Atlas is available ({{ .Version }}){{ with .Link }}: {{ . }}
{{ end }}
{{- with .Summary }}
{{ . }}
{{- end }}
{{- end }}
================================================
FILE: cmd/atlas/internal/cmdapi/vercheck/req_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package vercheck
import (
"context"
"net/http"
"ariga.io/atlas/cmd/atlas/internal/cloudapi"
)
func addHeaders(_ context.Context, req *http.Request) {
req.Header.Set("User-Agent", cloudapi.UserAgent())
}
================================================
FILE: cmd/atlas/internal/cmdapi/vercheck/vercheck.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package vercheck
import (
"context"
_ "embed"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"text/template"
"time"
"ariga.io/atlas/cmd/atlas/internal/cmdstate"
)
// StateFileName is the name of the file where the vercheck state is stored.
const StateFileName = "release.json"
// New returns a new VerChecker for the endpoint.
func New(endpoint string) *VerChecker {
return &VerChecker{
endpoint: endpoint,
state: &cmdstate.File[State]{Name: StateFileName},
}
}
type (
// Latest contains information about the most recent version.
Latest struct {
// Version is the new version name.
Version string
// Summary contains a brief description of the new version.
Summary string
// Link is a URL to a web page describing the new version.
Link string
}
// Advisory contains contents of security advisories.
Advisory struct {
Text string `json:"text"`
}
// Payload returns information to the client about their existing version of a component.
Payload struct {
// Latest is set if there is a newer version to upgrade to.
Latest *Latest `json:"latest"`
// Advisory is set if security advisories exist for the current version.
Advisory *Advisory `json:"advisory"`
}
// VerChecker retrieves version information from the vercheck service.
VerChecker struct {
endpoint string
state *cmdstate.File[State]
}
// State stores information about local runs of VerChecker to limit the
// frequency in which clients poll the service for information.
State struct {
CheckedAt time.Time `json:"checkedat"`
}
)
var (
// errSkip is returned when check isn't run because 24 hours haven't passed from the previous run.
errSkip = errors.New("skip vercheck")
// Notify is the template for displaying the payload to the user.
Notify *template.Template
)
// Check makes an HTTP request to endpoint to check if a new version or security advisories
// exist for the current version. Check tries to read the latest time it was run from the
// statePath, if found and 24 hours have not passed the check is skipped. When done, the latest
// time is updated in statePath.
func (v *VerChecker) Check(ctx context.Context, ver string) (*Payload, error) {
if err := v.verifyTime(); err != nil {
return nil, err
}
endpoint, err := url.JoinPath(v.endpoint, "atlas", ver)
if err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodGet, endpoint, nil)
if err != nil {
return nil, err
}
addHeaders(ctx, req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status: %s", resp.Status)
}
var p Payload
if err := json.NewDecoder(resp.Body).Decode(&p); err != nil {
return nil, err
}
if err := v.state.Write(State{CheckedAt: time.Now()}); err != nil {
return nil, err
}
return &p, nil
}
func (v *VerChecker) verifyTime() error {
s, err := v.state.Read()
if err != nil || time.Since(s.CheckedAt) >= (time.Hour*24) {
return nil
}
return errSkip
}
//go:embed notification.tmpl
var notifyTmpl string
func init() {
var err error
Notify, err = template.New("").Parse(notifyTmpl)
if err != nil {
panic(err)
}
}
================================================
FILE: cmd/atlas/internal/cmdapi/vercheck/vercheck_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package vercheck
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"runtime"
"testing"
"time"
"ariga.io/atlas/cmd/atlas/internal/cloudapi"
"ariga.io/atlas/cmd/atlas/internal/cmdstate"
"github.com/stretchr/testify/require"
)
func TestVerCheck(t *testing.T) {
var path, ua string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
output := `{"latest":{"Version":"v0.7.2","Summary":"","Link":"https://github.com/ariga/atlas/releases/tag/v0.7.2"},"advisory":null}`
path = r.URL.Path
ua = r.Header.Get("User-Agent")
_, _ = w.Write([]byte(output))
}))
defer srv.Close()
home := cmdstate.TestingHome(t)
vc := New(srv.URL)
ver := "v0.1.2"
check, err := vc.Check(context.Background(), ver)
require.EqualValues(t, "/atlas/"+ver, path)
cloudapi.SetVersion(ver, "")
expUA := fmt.Sprintf("Atlas/development (%s/%s)", runtime.GOOS, runtime.GOARCH)
require.EqualValues(t, expUA, ua)
require.NoError(t, err)
require.EqualValues(t, &Payload{
Latest: &Latest{
Version: "v0.7.2",
Summary: "",
Link: "https://github.com/ariga/atlas/releases/tag/v0.7.2",
},
}, check)
dirs, err := os.ReadDir(filepath.Join(home, ".atlas"))
require.NoError(t, err)
require.Len(t, dirs, 1)
}
func TestState(t *testing.T) {
hrAgo, err := json.Marshal(State{CheckedAt: time.Now().Add(-time.Hour)})
require.NoError(t, err)
weekAgo, err := json.Marshal(State{CheckedAt: time.Now().Add(-time.Hour * 24 * 7)})
require.NoError(t, err)
for _, tt := range []struct {
name string
state string
expectedRun bool
}{
{
name: "corrupt json",
state: "{",
expectedRun: true,
},
{
name: "none",
state: "", // no file
expectedRun: true,
},
{
name: "one hr ago",
state: string(hrAgo),
expectedRun: false,
},
{
name: "one week ago",
state: string(weekAgo),
expectedRun: true,
},
} {
t.Run(tt.name, func(t *testing.T) {
var ran bool
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ran = true
_, _ = w.Write([]byte(`{}`))
}))
t.Cleanup(srv.Close)
home := cmdstate.TestingHome(t)
path := filepath.Join(home, ".atlas", StateFileName)
if tt.state != "" {
require.NoError(t, os.MkdirAll(filepath.Dir(path), os.ModePerm))
require.NoError(t, os.WriteFile(path, []byte(tt.state), 0666))
}
vc := New(srv.URL)
_, _ = vc.Check(context.Background(), "v0.1.2")
require.EqualValues(t, tt.expectedRun, ran)
buf, err := os.ReadFile(path)
require.NoError(t, err)
if tt.expectedRun {
require.NotEqualValues(t, tt.state, buf)
} else {
require.EqualValues(t, tt.state, buf)
}
})
}
}
func TestStatePersist(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(`{}`))
}))
t.Cleanup(srv.Close)
home := cmdstate.TestingHome(t)
path := filepath.Join(home, ".atlas", StateFileName)
vc := New(srv.URL)
_, err := vc.Check(context.Background(), "v0.1.2")
require.NoError(t, err)
b, err := os.ReadFile(path)
require.NoError(t, err)
require.Contains(t, string(b), `"checkedat":`)
}
func TestTemplate(t *testing.T) {
for _, tt := range []struct {
name string
payload Payload
exp string
}{
{
name: "empty",
payload: Payload{},
exp: "",
},
{
name: "version with summary",
payload: Payload{
Latest: &Latest{
Version: "v0.7.2",
Summary: "A great version including amazing features.",
Link: "https://atlasgo.io/v0.7.2",
},
},
exp: `A new version of Atlas is available (v0.7.2): https://atlasgo.io/v0.7.2
A great version including amazing features.`,
},
{
name: "version",
payload: Payload{
Latest: &Latest{
Version: "v0.7.2",
Link: "https://atlasgo.io/v0.7.2",
},
},
exp: `A new version of Atlas is available (v0.7.2): https://atlasgo.io/v0.7.2
`,
},
{
name: "with advisory",
payload: Payload{
Advisory: &Advisory{Text: "This version contains a vulnerability, please upgrade."},
},
exp: `SECURITY ADVISORY
This version contains a vulnerability, please upgrade.`,
},
} {
t.Run(tt.name, func(t *testing.T) {
var b bytes.Buffer
err := Notify.Execute(&b, tt.payload)
require.NoError(t, err)
require.EqualValues(t, tt.exp, b.String())
})
}
}
================================================
FILE: cmd/atlas/internal/cmdapi/version_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent && !official
package cmdapi
const (
versionFmt = "atlas unofficial "
versionInfo = "To download an official version, visit: https://atlasgo.io/getting-started#installation\n"
)
================================================
FILE: cmd/atlas/internal/cmdapi/version_oss_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent && !official
package cmdapi
import (
"bytes"
"os"
"os/exec"
"testing"
"github.com/stretchr/testify/require"
)
func TestCLI_Version(t *testing.T) {
tests := []struct {
name string
cmd *exec.Cmd
expected string
}{
{
name: "dev mode",
cmd: exec.Command("go", "run", "ariga.io/atlas/cmd/atlas",
"version",
),
expected: "atlas unofficial version - development\nhttps://github.com/ariga/atlas/releases/latest\n",
},
{
name: "release",
cmd: exec.Command("go", "run",
"-ldflags",
"-X ariga.io/atlas/cmd/atlas/internal/cmdapi.version=v1.2.3",
"ariga.io/atlas/cmd/atlas",
"version",
),
expected: "atlas unofficial version v1.2.3\nhttps://github.com/ariga/atlas/releases/tag/v1.2.3\n",
},
{
name: "canary",
cmd: exec.Command("go", "run",
"-ldflags",
"-X ariga.io/atlas/cmd/atlas/internal/cmdapi.version=v0.3.0-6539f2704b5d-canary",
"ariga.io/atlas/cmd/atlas",
"version",
),
expected: "atlas unofficial version v0.3.0-6539f2704b5d-canary\nhttps://github.com/ariga/atlas/releases/latest\n",
},
{
name: "flavor",
cmd: exec.Command("go", "run",
"-ldflags",
"-X ariga.io/atlas/cmd/atlas/internal/cmdapi.flavor=flavor",
"ariga.io/atlas/cmd/atlas",
"version",
),
expected: "atlas unofficial flavor version - development\nhttps://github.com/ariga/atlas/releases/latest\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("ATLAS_NO_UPDATE_NOTIFIER", "true")
stdout := bytes.NewBuffer(nil)
tt.cmd.Stdout = stdout
tt.cmd.Stderr = os.Stderr
require.NoError(t, tt.cmd.Run())
require.Equal(t, tt.expected+versionInfo, stdout.String())
})
}
}
================================================
FILE: cmd/atlas/internal/cmdext/cmdext.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Package cmdext provides extensions to the Atlas configuration
// file such as schema loaders, data sources and cloud connectors.
package cmdext
import (
"bytes"
"context"
"errors"
"fmt"
"io/fs"
"net/url"
"os"
"os/exec"
"path"
"path/filepath"
"text/template"
"time"
"ariga.io/atlas/cmd/atlas/internal/cloudapi"
"ariga.io/atlas/schemahcl"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/rds/auth"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/gocty"
"gocloud.dev/runtimevar"
_ "gocloud.dev/runtimevar/awsparamstore"
_ "gocloud.dev/runtimevar/awssecretsmanager"
_ "gocloud.dev/runtimevar/constantvar"
_ "gocloud.dev/runtimevar/filevar"
_ "gocloud.dev/runtimevar/gcpruntimeconfig"
_ "gocloud.dev/runtimevar/gcpsecretmanager"
_ "gocloud.dev/runtimevar/httpvar"
"golang.org/x/oauth2/google"
sqladmin "google.golang.org/api/sqladmin/v1beta4"
)
// SpecOptions exposes the schema spec options like data-sources provided by this package.
var SpecOptions = append(
[]schemahcl.Option{
schemahcl.WithDataSource("sql", Query),
schemahcl.WithDataSource("external", External),
schemahcl.WithDataSource("runtimevar", RuntimeVar),
schemahcl.WithDataSource("template_dir", TemplateDir),
schemahcl.WithDataSource("remote_dir", RemoteDir),
schemahcl.WithDataSource("remote_schema", RemoteSchema),
schemahcl.WithDataSource("hcl_schema", SchemaHCL),
schemahcl.WithDataSource("external_schema", SchemaExternal),
schemahcl.WithDataSource("aws_rds_token", AWSRDSToken),
schemahcl.WithDataSource("gcp_cloudsql_token", GCPCloudSQLToken),
},
specOptions...,
)
// AtlasConfig exposes non-sensitive information returned by the "atlas" init-block.
// By invoking AtlasInitBlock() a new config is returned that is set by the init block
// defined and executed on schemahcl Eval functions.
type AtlasConfig struct {
Client *cloudapi.Client // Client attached to Atlas Cloud.
Token string // User token.
Org string // Organization to connect to.
Project string // Optional project.
}
// RuntimeVar exposes the gocloud.dev/runtimevar as a schemahcl datasource.
//
// data "runtimevar" "pass" {
// url = "driver://path?query=param"
// }
//
// locals {
// url = "mysql://root:${data.runtimevar.pass}@:3306/"
// }
func RuntimeVar(ctx context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {
var (
args struct {
URL string `hcl:"url"`
}
errorf = blockError("data.runtimevar", block)
)
if diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {
return cty.NilVal, errorf("decoding body: %v", diags)
}
u, err := sqlclient.ParseURL(args.URL)
if err != nil {
return cty.NilVal, errorf("parsing url: %v", err)
}
if d := u.Query().Get("decoder"); d != "" && d != "string" {
return cty.NilVal, errorf("unsupported decoder: %q", d)
}
q := u.Query()
q.Set("decoder", "string")
// Default timeout is 10s unless specified otherwise.
timeout := 10 * time.Second
if t := q.Get("timeout"); t != "" {
if timeout, err = time.ParseDuration(t); err != nil {
return cty.NilVal, errorf("parsing timeout: %v", err)
}
q.Del("timeout")
}
u.RawQuery = q.Encode()
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
vr, err := runtimevar.OpenVariable(ctx, u.String())
if err != nil {
return cty.Value{}, errorf("opening variable: %v", err)
}
defer vr.Close()
snap, err := vr.Latest(ctx)
if err != nil {
return cty.Value{}, errorf("getting latest snapshot: %v", err)
}
sv, ok := snap.Value.(string)
if !ok {
return cty.Value{}, errorf("unexpected snapshot value type: %T", snap.Value)
}
return cty.StringVal(sv), nil
}
// AWSRDSToken exposes an AWS RDS token as a schemahcl datasource.
//
// data "aws_rds_token" "token" {
// endpoint = "db.hostname.io:3306"
// region = "us-east-1"
// username = "admin"
// profile = "prod-ext"
// }
func AWSRDSToken(ctx context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {
var (
args struct {
Endpoint string `hcl:"endpoint"`
Region string `hcl:"region,optional"`
Username string `hcl:"username"`
Profile string `hcl:"profile,optional"`
}
errorf = blockError("data.aws_rds_token", block)
)
if diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {
return cty.NilVal, errorf("decoding body: %v", diags)
}
cfg, err := config.LoadDefaultConfig(
ctx,
config.WithSharedConfigProfile(args.Profile), // Ignored if empty.
)
if err != nil {
return cty.NilVal, errorf("loading aws config: %v", err)
}
if args.Region == "" {
args.Region = cfg.Region
}
token, err := auth.BuildAuthToken(ctx, args.Endpoint, args.Region, args.Username, cfg.Credentials)
if err != nil {
return cty.NilVal, errorf("building auth token: %v", err)
}
return cty.StringVal(token), nil
}
// GCPCloudSQLToken exposes a CloudSQL token as a schemahcl datasource.
//
// data "gcp_cloudsql_token" "hello" {}
func GCPCloudSQLToken(ctx context.Context, _ *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {
errorf := blockError("data.gcp_cloudsql_token", block)
ts, err := google.DefaultTokenSource(ctx, sqladmin.SqlserviceAdminScope)
if err != nil {
return cty.NilVal, errorf("finding default credentials: %v", err)
}
token, err := ts.Token()
if err != nil {
return cty.NilVal, errorf("getting token: %v", err)
}
return cty.StringVal(token.AccessToken), nil
}
// Query exposes the database/sql.Query as a schemahcl datasource.
//
// data "sql" "tenants" {
// url = var.url
// query =
// args = [, , ...]
// }
//
// env "prod" {
// for_each = toset(data.sql.tenants.values)
// url = urlsetpath(var.url, each.value)
// }
func Query(ctx context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {
var (
args struct {
URL string `hcl:"url"`
Query string `hcl:"query"`
Remain hcl.Body `hcl:",remain"`
Args []any
}
values []cty.Value
errorf = blockError("data.sql", block)
)
if diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {
return cty.NilVal, errorf("decoding body: %v", diags)
}
attrs, diags := args.Remain.JustAttributes()
if diags.HasErrors() {
return cty.NilVal, errorf("getting attributes: %v", diags)
}
if at, ok := attrs["args"]; ok {
switch v, diags := at.Expr.Value(ectx); {
case diags.HasErrors():
return cty.NilVal, errorf(`evaluating "args": %w`, diags)
case !v.CanIterateElements():
return cty.NilVal, errorf(`attribute "args" must be a list, got: %s`, v.Type())
default:
for it := v.ElementIterator(); it.Next(); {
switch _, v := it.Element(); v.Type() {
case cty.String:
args.Args = append(args.Args, v.AsString())
case cty.Number:
f, _ := v.AsBigFloat().Float64()
args.Args = append(args.Args, f)
case cty.Bool:
args.Args = append(args.Args, v.True())
default:
return cty.NilVal, errorf(`attribute "args" must be a list of strings, numbers or booleans, got: %s`, v.Type())
}
}
}
delete(attrs, "args")
}
if len(attrs) > 0 {
return cty.NilVal, errorf("unexpected attributes: %v", attrs)
}
c, err := sqlclient.Open(ctx, args.URL)
if err != nil {
return cty.NilVal, errorf("opening connection: %w", err)
}
defer c.Close()
rows, err := c.QueryContext(ctx, args.Query, args.Args...)
if err != nil {
return cty.NilVal, errorf("executing query: %w", err)
}
defer rows.Close()
for rows.Next() {
var v any
if err := rows.Scan(&v); err != nil {
return cty.NilVal, errorf("scanning row: %w", err)
}
switch v := v.(type) {
case bool:
values = append(values, cty.BoolVal(v))
case int64:
values = append(values, cty.NumberIntVal(v))
case float64:
values = append(values, cty.NumberFloatVal(v))
case string:
values = append(values, cty.StringVal(v))
case []byte:
values = append(values, cty.StringVal(string(v)))
default:
return cty.NilVal, errorf("unsupported row type: %T", v)
}
}
obj := map[string]cty.Value{
"count": cty.NumberIntVal(int64(len(values))),
"values": cty.ListValEmpty(cty.NilType),
"value": cty.NilVal,
}
if len(values) > 0 {
obj["value"] = values[0]
obj["values"] = cty.ListVal(values)
}
return cty.ObjectVal(obj), nil
}
// External allows loading data using external program execution.
//
// data "external" "env1" {
// program = [
// "node",
// loadenv.js",
// ]
// }
//
// data "external" "env2" {
// program = [
// "bash",
// "-c",
// "env_to_json --file=${var.envfile} | jq '...' ",
// ]
// }
func External(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {
var (
args struct {
Program []string `hcl:"program"`
Dir string `hcl:"working_dir,optional"`
Remain hcl.Body `hcl:",remain"`
}
errorf = blockError("data.external", block)
)
if diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {
return cty.NilVal, errorf("decoding body: %v", diags)
}
attrs, diags := args.Remain.JustAttributes()
if diags.HasErrors() {
return cty.NilVal, errorf("getting attributes: %v", diags)
}
if len(attrs) > 0 {
return cty.NilVal, errorf("unexpected attributes: %v", attrs)
}
if len(args.Program) == 0 {
return cty.NilVal, errorf("program cannot be empty")
}
cmd := exec.Command(args.Program[0], args.Program[1:]...)
if args.Dir != "" {
cmd.Dir = args.Dir
}
out, err := cmd.Output()
if err != nil {
msg := err.Error()
if err1 := (*exec.ExitError)(nil); errors.As(err, &err1) && len(err1.Stderr) > 0 {
msg = string(err1.Stderr)
}
return cty.NilVal, errorf("running program %v: %v", cmd.Path, msg)
}
return cty.StringVal(string(out)), nil
}
// TemplateDir implements migrate.Dir interface for template directories.
//
// data "template_dir" "name" {
// path = "path/to/directory"
// vars = {
// Env = atlas.env
// Seed = var.seed
// }
// }
//
// env "dev" {
// url = "driver://path?query=param"
// migration {
// dir = data.template_dir.name.url
// }
// }
func TemplateDir(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {
var (
args struct {
Path string `hcl:"path"`
Remain hcl.Body `hcl:",remain"`
}
vars = make(map[string]any)
errorf = blockError("data.template_dir", block)
)
if diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {
return cty.NilVal, errorf("decoding body: %v", diags)
}
attrs, diags := args.Remain.JustAttributes()
if diags.HasErrors() {
return cty.NilVal, errorf("getting attributes: %v", diags)
}
if vs, ok := attrs["vars"]; ok {
switch vs, diags := vs.Expr.Value(ectx); {
case diags.HasErrors():
return cty.NilVal, errorf(`evaluating "vars": %w`, diags)
case !vs.CanIterateElements():
return cty.NilVal, errorf(`attribute "vars" must be a map, got: %s`, vs.Type())
default:
for it := vs.ElementIterator(); it.Next(); {
k, v := it.Element()
switch v.Type() {
case cty.String:
vars[k.AsString()] = v.AsString()
case cty.Number:
f, _ := v.AsBigFloat().Float64()
vars[k.AsString()] = f
case cty.Bool:
vars[k.AsString()] = v.True()
case cty.List(cty.String):
var s []string
if err := gocty.FromCtyValue(v, &s); err != nil {
return cty.NilVal, errorf("convert strings: %w", err)
}
vars[k.AsString()] = s
case cty.List(cty.Number):
var s []float64
if err := gocty.FromCtyValue(v, &s); err != nil {
return cty.NilVal, errorf("convert floats: %w", err)
}
vars[k.AsString()] = s
case cty.List(cty.Bool):
var s []bool
if err := gocty.FromCtyValue(v, &s); err != nil {
return cty.NilVal, errorf("convert bools: %w", err)
}
vars[k.AsString()] = s
default:
return cty.NilVal, errorf(`attribute "vars" must be a map of strings, numbers or booleans, got: %s`, v.Type().FriendlyName())
}
}
}
delete(attrs, "vars")
}
if len(attrs) > 0 {
return cty.NilVal, errorf("unexpected attributes: %v", attrs)
}
if d, err := os.Stat(args.Path); err != nil || !d.IsDir() {
return cty.NilVal, errorf("path %s is not a directory", args.Path)
}
dirname := path.Join(args.Path, block.Labels[1])
dir := migrate.OpenMemDir(dirname)
dir.SetPath(args.Path)
// Clear existing directories in case the config was called
// multiple times with different variables.
if files, err := dir.Files(); err != nil || len(files) > 0 {
dir.Reset()
}
t := template.New("template_dir").Option("missingkey=error")
err := filepath.Walk(args.Path, func(path string, d os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("walk path %s: %w", path, err)
}
if !d.IsDir() {
_, err = t.ParseFiles(path)
}
return err
})
if err != nil {
return cty.NilVal, errorf(err.Error())
}
// Only top-level (template) files are treated as migrations.
matches, err := fs.Glob(os.DirFS(args.Path), "*.sql")
if err != nil {
return cty.NilVal, errorf("globbing templates: %w", err)
}
for _, m := range matches {
var b bytes.Buffer
if err := t.ExecuteTemplate(&b, m, vars); err != nil {
return cty.NilVal, errorf("executing template: %w", err)
}
if err := dir.WriteFile(m, b.Bytes()); err != nil {
return cty.NilVal, errorf("writing file %q: %w", m, err)
}
}
sum, err := dir.Checksum()
if err != nil {
return cty.NilVal, err
}
if err := migrate.WriteSumFile(dir, sum); err != nil {
return cty.NilVal, err
}
// Sync template dir to local filesystem.
dir.SyncWrites(func(name string, data []byte) error {
if name == migrate.HashFileName {
return nil
}
l, err := migrate.NewLocalDir(args.Path)
if err != nil {
return err
}
if err := l.WriteFile(name, data); err != nil {
return err
}
sum, err := l.Checksum()
if err != nil {
return err
}
return migrate.WriteSumFile(l, sum)
})
u := fmt.Sprintf("mem://%s", dirname)
// Allow using reading the computed dir as a state source.
memLoader.states[u] = StateLoaderFunc(func(ctx context.Context, config *StateReaderConfig) (*StateReadCloser, error) {
return stateReaderSQL(ctx, config, dir, nil, nil)
})
return cty.ObjectVal(map[string]cty.Value{
"url": cty.StringVal(u),
}), nil
}
// SchemaHCL is a data source that reads an Atlas HCL schema file(s), evaluates it
// with the given variables and exposes its resulting schema as in-memory HCL file.
func SchemaHCL(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {
var (
args struct {
Paths []string `hcl:"paths,optional"`
Path string `hcl:"path,optional"`
Vars map[string]cty.Value `hcl:"vars,optional"`
Remain hcl.Body `hcl:",remain"`
}
errorf = blockError("data.hcl_schema", block)
)
if diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {
return cty.NilVal, errorf("decoding body: %v", diags)
}
attrs, diags := args.Remain.JustAttributes()
if diags.HasErrors() {
return cty.NilVal, errorf("getting attributes: %v", diags)
}
if len(attrs) > 0 {
return cty.NilVal, errorf("unexpected attributes: %v", attrs)
}
paths := args.Paths
switch {
case len(paths) != 0:
if args.Path != "" {
return cty.NilVal, errorf("path and paths cannot be set together")
}
case args.Path == "":
return cty.NilVal, errorf("path or paths must be set")
default:
paths = []string{args.Path}
}
u, err := url.JoinPath("mem://hcl_schema", block.Labels[1])
if err != nil {
return cty.NilVal, errorf("build url: %v", err)
}
memLoader.states[u] = StateLoaderFunc(func(ctx context.Context, config *StateReaderConfig) (*StateReadCloser, error) {
cfg := *config
cfg.Vars = args.Vars
return stateReaderHCL(ctx, &cfg, paths)
})
return cty.ObjectVal(map[string]cty.Value{
"url": cty.StringVal(u),
}), nil
}
func blockError(name string, b *hclsyntax.Block) func(string, ...any) error {
return func(format string, args ...any) error {
return fmt.Errorf("%s.%s: %w", name, b.Labels[1], fmt.Errorf(format, args...))
}
}
type (
// StateLoader allows loading StateReader's from external sources.
StateLoader interface {
LoadState(context.Context, *StateReaderConfig) (*StateReadCloser, error)
}
// The StateLoaderFunc type is an adapter to allow the use of ordinary
// function as StateLoader.
StateLoaderFunc func(context.Context, *StateReaderConfig) (*StateReadCloser, error)
// MigrateDiffOptions for external migration differ.
MigrateDiffOptions struct {
Name string
Indent string
To []string
Dir migrate.Dir
Dev *sqlclient.Client
Options []schema.DiffOption
}
// MigrateDiffer allows external sources to implement custom migration differs.
MigrateDiffer interface {
MigrateDiff(context.Context, *MigrateDiffOptions) error
needDiff([]string) bool
}
)
// LoadState calls f(ctx, opts).
func (f StateLoaderFunc) LoadState(ctx context.Context, opts *StateReaderConfig) (*StateReadCloser, error) {
return f(ctx, opts)
}
var (
// States is a global registry for external state loaders.
States = registry{
"ent": EntLoader{},
"mem": memLoader,
}
memLoader = MemLoader{states: make(map[string]StateLoader)}
errNotSchemaURL = errors.New("missing schema in --dev-url. See: https://atlasgo.io/url")
)
type registry map[string]StateLoader
// HasLoader returns true if the given scheme is registered.
func (r registry) HasLoader(scheme string) bool {
_, ok := r[scheme]
return ok
}
// Loader returns the state loader for the given scheme.
func (r registry) Loader(scheme string) (StateLoader, bool) {
l, ok := r[scheme]
return l, ok
}
// Differ returns the raw states differ for the given URLs, if registered.
func (r registry) Differ(to []string) (MigrateDiffer, bool) {
for _, l := range r {
if d, ok := l.(MigrateDiffer); ok && d.needDiff(to) {
return d, true
}
}
return nil, false
}
// MemLoader is a StateLoader for loading data-sources
// that were loaded into program memory.
type MemLoader struct {
states map[string]StateLoader
}
// LoadState loads the state loaded from data-sources into memory.
func (l MemLoader) LoadState(ctx context.Context, config *StateReaderConfig) (*StateReadCloser, error) {
if len(config.URLs) != 1 {
return nil, errors.New(`"mem://" requires exactly one data-source URL`)
}
u := config.URLs[0].String()
if l.states[u] == nil {
return nil, fmt.Errorf("data-source state %q not found in memory", u)
}
return l.states[u].LoadState(ctx, config)
}
================================================
FILE: cmd/atlas/internal/cmdext/cmdext_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package cmdext
import (
"bytes"
"context"
"fmt"
"os"
"path/filepath"
"runtime"
cmdmigrate "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/schemahcl"
"ariga.io/atlas/sql/migrate"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"
)
var specOptions []schemahcl.Option
// RemoteSchema is a data source that for reading remote schemas.
func RemoteSchema(context.Context, *hcl.EvalContext, *hclsyntax.Block) (cty.Value, error) {
return cty.Zero, UnsupportedErr("data.remote_schema")
}
// RemoteDir is a data source that reads a remote migration directory.
func RemoteDir(context.Context, *hcl.EvalContext, *hclsyntax.Block) (cty.Value, error) {
return cty.Zero, UnsupportedErr("data.remote_dir")
}
// StateReaderAtlas returns a migrate.StateReader from an Atlas Cloud schema.
func StateReaderAtlas(context.Context, *StateReaderConfig) (*StateReadCloser, error) {
return nil, UnsupportedErr("atlas remote state")
}
// SchemaExternal is a data source that for reading external schemas.
func SchemaExternal(context.Context, *hcl.EvalContext, *hclsyntax.Block) (cty.Value, error) {
return cty.Zero, UnsupportedErr("data.external_schema")
}
// EntLoader is a StateLoader for loading ent.Schema's as StateReader's.
type EntLoader struct{}
// LoadState returns a migrate.StateReader that reads the schema from an ent.Schema.
func (l EntLoader) LoadState(context.Context, *StateReaderConfig) (*StateReadCloser, error) {
return nil, UnsupportedErr("ent:// scheme")
}
// MigrateDiff returns the diff between ent.Schema and a directory.
func (l EntLoader) MigrateDiff(context.Context, *MigrateDiffOptions) error {
return UnsupportedErr("ent:// scheme")
}
// InitBlock returns the handler for the "atlas" init block.
func (c *AtlasConfig) InitBlock() schemahcl.Option {
return schemahcl.WithInitBlock("atlas", func(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {
return cty.Zero, UnsupportedErr("atlas block")
})
}
// StateReaderSQL returns a migrate.StateReader from an SQL file or a directory of migrations.
func StateReaderSQL(ctx context.Context, config *StateReaderConfig) (*StateReadCloser, error) {
if len(config.URLs) != 1 {
return nil, fmt.Errorf("the provided SQL state must be either a single schema file or a migration directory, but %d paths were found", len(config.URLs))
}
var (
dir migrate.Dir
path = filepath.Join(config.URLs[0].Host, config.URLs[0].Path)
)
switch fi, err := os.Stat(path); {
case err != nil:
return nil, err
// A single schema file.
case !fi.IsDir():
b, err := os.ReadFile(path)
if err != nil {
return nil, err
}
if bytes.Contains(b, []byte("-- atlas:import ")) {
return nil, UnsupportedErr("atlas:import directive")
}
if dir, err = FilesAsDir(migrate.NewLocalFile(fi.Name(), b)); err != nil {
return nil, err
}
return stateSchemaSQL(ctx, config, dir)
// The sum file is optional when reading the directory state.
case isSchemaDir(config.URLs[0], path):
dirs, err := os.ReadDir(path)
if err != nil {
return nil, err
}
files := make([]migrate.File, 0, len(dirs))
for _, d := range dirs {
b, err := os.ReadFile(filepath.Join(path, d.Name()))
if err != nil {
return nil, err
}
if bytes.Contains(b, []byte("-- atlas:import ")) {
return nil, UnsupportedErr("atlas:import directive")
}
files = append(files, migrate.NewLocalFile(d.Name(), b))
}
if dir, err = FilesAsDir(files...); err != nil {
return nil, err
}
return stateSchemaSQL(ctx, config, dir)
// A migration directory.
default:
var opts []migrate.ReplayOption
if dir, err = cmdmigrate.DirURL(ctx, config.URLs[0], false); err != nil {
return nil, err
}
if v := config.URLs[0].Query().Get("version"); v != "" {
opts = append(opts, migrate.ReplayToVersion(v))
}
return stateReaderSQL(ctx, config, dir, nil, opts)
}
}
// UnsupportedError wraps the standard message
// used to present an unsupported feature error.
type UnsupportedError struct {
Err error
}
// IsAbort implements the cmdapi.Aborter interface.
func (*UnsupportedError) IsAbort() {}
func UnsupportedErr(feature string) error {
switch runtime.GOOS {
case "windows":
return fmt.Errorf(`%s is not supported by the community version of Atlas.
Install the non-community version instead: https://atlasgo.io/docs#installation`, feature)
default:
return fmt.Errorf(`%s is not supported by the community version of Atlas.
Install the non-community version instead:
curl -sSf https://atlasgo.sh | sh
For more installtion options, see: https://atlasgo.io/docs#installation`, feature)
}
}
================================================
FILE: cmd/atlas/internal/cmdext/cmdext_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdext_test
import (
"context"
"encoding/base64"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
"strings"
"testing"
"ariga.io/atlas/cmd/atlas/internal/cmdext"
"ariga.io/atlas/schemahcl"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/sqlclient"
_ "ariga.io/atlas/sql/sqlite"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
"github.com/zclconf/go-cty/cty"
)
func TestRuntimeVarSrc(t *testing.T) {
var (
v struct {
V string `spec:"v"`
}
state = schemahcl.New(cmdext.SpecOptions...)
)
err := state.EvalBytes([]byte(`
data "runtimevar" "pass" {
url = "constant://?val=hello+world&decoder=binary"
}
v = data.runtimevar.pass
`), &v, nil)
require.EqualError(t, err, `data.runtimevar.pass: unsupported decoder: "binary"`)
err = state.EvalBytes([]byte(`
data "runtimevar" "pass" {
url = "constant://?val=hello+world"
}
v = data.runtimevar.pass
`), &v, nil)
require.NoError(t, err)
require.Equal(t, v.V, "hello world")
err = state.EvalBytes([]byte(`
data "runtimevar" "pass" {
url = "constant://?val=hello+world&decoder=string"
}
v = data.runtimevar.pass
`), &v, nil)
require.NoError(t, err, "nop decoder")
require.Equal(t, v.V, "hello world")
}
func TestRDSToken(t *testing.T) {
t.Cleanup(
backupEnv("AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"),
)
// Mock AWS env vars.
require.NoError(t, os.Setenv("AWS_ACCESS_KEY_ID", "EXAMPLE_KEY_ID"))
require.NoError(t, os.Setenv("AWS_SECRET_ACCESS_KEY", "EXAMPLE_SECRET_KEY"))
var (
v struct {
V string `spec:"v"`
}
state = schemahcl.New(cmdext.SpecOptions...)
)
err := state.EvalBytes([]byte(`
data "aws_rds_token" "token" {
endpoint = "localhost:3306"
region = "us-east-1"
username = "root"
}
v = data.aws_rds_token.token
`), &v, nil)
require.NoError(t, err)
parse, err := url.Parse(v.V)
require.NoError(t, err)
q := parse.Query()
require.Equal(t, "connect", q.Get("Action"))
require.Contains(t, q.Get("X-Amz-Credential"), "EXAMPLE_KEY_ID")
}
// TestRDSTokenProfile verifies the profile option propagates to the AWS SDK.
func TestRDSTokenProfile(t *testing.T) {
doc := `
data "aws_rds_token" "token" {
username = "root"
endpoint = "localhost:3306"
region = "us-east-1"
profile = "errorneous"
}
v = data.aws_rds_token.token
`
var (
v struct {
V string `spec:"v"`
}
state = schemahcl.New(cmdext.SpecOptions...)
)
err := state.EvalBytes([]byte(doc), &v, nil)
require.EqualError(t, err, "data.aws_rds_token.token: loading aws config: failed to get shared config profile, errorneous")
}
func TestGCPToken(t *testing.T) {
t.Cleanup(
backupEnv("GOOGLE_APPLICATION_CREDENTIALS"),
)
credsFile := filepath.Join(t.TempDir(), "foo.json")
require.NoError(t, os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", credsFile))
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.String() != "/token" {
t.Errorf("Unexpected exchange request URL, %v is found.", r.URL)
}
jwt := r.FormValue("assertion")
payload, err := base64.RawStdEncoding.DecodeString(strings.Split(jwt, ".")[1])
require.NoError(t, err)
// Ensure we request correct scopes
require.Contains(t, string(payload), `"https://www.googleapis.com/auth/sqlservice.admin"`)
w.Header().Set("Content-Type", "application/json")
// Write a fake access token to the client
w.Write([]byte(`{"access_token":"foo-bar-token","scope":"user","token_type":"bearer","expires_in":86400}`))
}))
defer ts.Close()
require.NoError(t, os.WriteFile(credsFile, []byte(fmt.Sprintf(`{
"type": "service_account",
"project_id": "foo-bar",
"private_key_id": "foo-bar",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCxLnH1p8E1IiWw\nQrSv8BtXfOaFzPvYt6tcwsti9O3LhG6KtTEbXXbUe72tga5B8awQXYkRtdST2uV6\nhjvFHzmHzLOJVa/Qm1duO4iTkjz7Hj7kbfEI4dF5iLRn8+QF8YwGJCewSS8IXmbl\nu/4w64dtdC5h880p33gW73oNSLr6d6tlifc/oUAVdu4Bz8qSARpF+4nIN3uZGqr1\n8wqsHx9N5twaEO7Ky5ezNWv2TfiBk4hPtGJUWXPM++mKZpZcmpzXT9dP9gfPX0mN\np45FNXhjN8uA7aauqVzl2dWYmED32k1EGK2/m66lPq+IEo7p/90FUbvR/x+pbx0r\nYOgGKrhfAgMBAAECggEAVUWqGPVcmirOAq+H8GjZb9ivxVNrHdj/gwxJAF4ql9kr\nrlwXvzjTON444mlYKWqbSeEKV9iv71zZNoel+m/Vq1LMUVtI21f30xiZ2ZP2/1CG\nKj/zUjgELb6qPKF3a5jdsBL0evYtyZRNZ2F7q6WfLwFMVV4VroJbdIZaskv/mQzx\ny45FWU14/J/Vuk6Bqv0AtWb3ZSGnKGRWjOSlr9OI8nXEDg69LE3pGB3/XrPtfrbo\n7YdFC24DFUXRUIkNHnktQZ14U+0HmbPgs6OWUNvMfdvckP87e+7eoBiUkPrJA1wi\nrSm2ZW70Wvf1sD2h9kgpABe+cuWoqWTWBBXlfkuwUQKBgQD3MjGN8QIfhIKMEz9X\nFkL9BdFPswcawVaiTXfrhHtPmcJLmT5VGEnyh6jvigdKSpQe/s5IzLnFglqKO5Ge\nW57YiBVwfNREpzahJULaAL45NtwJtasSz1tNz3EKm00Z5o6tcCk2dZ6rzFKRY3Sz\nUfSo0lc7+rfNQzC4+GVlxTcNNwKBgQC3feTmNL917xceMwAA3g0nh+aHi4rPIN3H\nkhghDvCYMg4gYml/vZnUMkjfTsdS/TrXvIE1Pd6QDCSRx/VZFIBFA2P5c+g6l5fo\nBSS5CUm+R3j27NsGQXIfr5bANuKECjugZtbmsZ2taAtzLVjoO1yDDFBf9FWie9I8\nnbKmr9ACGQKBgQD2yt/6jEHIYa1MV/MG6SzcHDDK1zwilCAATkOJmWzbHfGDNG2s\n22EIiDQ7YpzAqRCUmWQt/mcCL5BhLfPGHEbMe6Cb+6SZHjBGVkMWD2PbD1BDSWKQ\nlwDbAF4lbsNdNnf/5FjhDDDr6EQO7zKVzR7sZYO+WCOlBI3iPexN3MWHpQKBgGYA\nxk5y5DxbPS68izPwPL/M/Io9OF0MmD1pKaC2/Wid6tx12M/6Rpl/mqMI2CV6QEvN\nrsY6Lo9FMM8ZqXpruyKiT+FMXby0qO2CbneugiAU+1nJMbi4iQi0Q8l2uVVNmvgA\nM1brRgwv2q2cd+Ahn7v6DHRLD4/T5Xts7vNaqPeBAoGAQZ/Yzp40aDvlv9D6MUKi\ngDvmjQPeI6H08MlCLTnbzJusf1nL3whVa5xbbp7+iVl0nMLzogxNC0dCNUUzdXov\n/PxhteomqwnQb9He0PSSYKQUoL+iHoTy3BY+jNPsCNsWgNm04k/vaB5le4zipc6M\npEWCIJtjmdEC1tzBtTEN1aY=\n-----END PRIVATE KEY-----\n",
"client_email": "foo@bar.iam.gserviceaccount.com",
"client_id": "100000000000000000000",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "%s/token",
"auth_provider_x509_cert_url": "",
"client_x509_cert_url": "",
"universe_domain": "googleapis.com"
}`, ts.URL)), 0644))
var (
v struct {
V string `spec:"v"`
}
state = schemahcl.New(cmdext.SpecOptions...)
)
err := state.EvalBytes([]byte(`
data "gcp_cloudsql_token" "helloworld" {}
v = data.gcp_cloudsql_token.helloworld
`), &v, nil)
require.NoError(t, err)
require.Equal(t, "foo-bar-token", v.V)
}
func TestQuerySrc(t *testing.T) {
ctx := context.Background()
u := fmt.Sprintf("sqlite3://file:%s?cache=shared&_fk=1", filepath.Join(t.TempDir(), "test.db"))
drv, err := sqlclient.Open(context.Background(), u)
require.NoError(t, err)
_, err = drv.ExecContext(ctx, "CREATE TABLE users (name text)")
require.NoError(t, err)
_, err = drv.ExecContext(ctx, "INSERT INTO users (name) VALUES ('a8m')")
require.NoError(t, err)
var (
v struct {
C int `spec:"c"`
V string `spec:"v"`
Vs []string `spec:"vs"`
}
state = schemahcl.New(cmdext.SpecOptions...)
)
err = state.EvalBytes([]byte(fmt.Sprintf(`
data "sql" "user" {
url = %q
query = "SELECT name FROM users"
}
c = data.sql.user.count
v = data.sql.user.value
vs = data.sql.user.values
`, u)), &v, nil)
require.NoError(t, err)
require.Equal(t, 1, v.C)
require.Equal(t, "a8m", v.V)
require.Equal(t, []string{"a8m"}, v.Vs)
}
func TestTemplateDir(t *testing.T) {
var (
v struct {
Dir string `spec:"dir"`
}
dir = t.TempDir()
ctx = context.Background()
state = schemahcl.New(cmdext.SpecOptions...)
// language=hcl
cfg = `
variable "path" {
type = string
}
data "template_dir" "tenant" {
path = var.path
vars = {
Schema = "main"
}
}
dir = data.template_dir.tenant.url
`
)
err := os.WriteFile(filepath.Join(dir, "1.sql"), []byte("create table {{ .Schema }}.t(c int);"), 0644)
require.NoError(t, err)
err = state.EvalBytes([]byte(cfg), &v, map[string]cty.Value{
"path": cty.StringVal(dir),
})
require.NoError(t, err)
require.NotEmpty(t, v.Dir)
d := migrate.OpenMemDir(strings.TrimPrefix(v.Dir, "mem://"))
require.NoError(t, migrate.Validate(d))
files, err := d.Files()
require.NoError(t, err)
require.Len(t, files, 1)
require.Equal(t, "1.sql", files[0].Name())
require.Equal(t, "create table main.t(c int);", string(files[0].Bytes()))
// Directory was loaded to memory as source for readers.
mem, ok := cmdext.States.Loader("mem")
require.True(t, ok)
u, err := url.Parse(v.Dir)
require.NoError(t, err)
dev, err := sqlclient.Open(ctx, "sqlite://test?mode=memory")
require.NoError(t, err)
sr, err := mem.LoadState(ctx, &cmdext.StateReaderConfig{
URLs: []*url.URL{u},
Dev: dev,
})
require.NoError(t, err)
r, err := sr.ReadState(ctx)
require.NoError(t, err)
require.Len(t, r.Schemas[0].Tables, 1)
// Should not accept non-directories.
err = state.EvalBytes([]byte(cfg), &v, map[string]cty.Value{
"path": cty.StringVal(filepath.Join(dir, "1.sql")),
})
require.ErrorContains(t, err, "data.template_dir.tenant: path", "error prefix")
require.ErrorContains(t, err, "1.sql is not a directory", "error suffix")
}
func TestSchemaHCL(t *testing.T) {
var (
v struct {
Schema string `spec:"schema"`
}
dir = t.TempDir()
ctx = context.Background()
state = schemahcl.New(cmdext.SpecOptions...)
)
err := os.WriteFile(filepath.Join(dir, "schema.hcl"), []byte(`
variable "schema" {
type = string
}
schema "dynamic" {
name = var.schema
}
table "t" {
schema = schema.dynamic
column "c" {
type = int
}
}
`), 0644)
require.NoError(t, err)
err = state.EvalBytes([]byte(`
variable "path" {
type = string
}
data "hcl_schema" "a8m" {
path = var.path
vars = {
schema = "a8m"
}
}
schema = data.hcl_schema.a8m.url
`), &v, map[string]cty.Value{
"path": cty.StringVal(dir),
})
require.NoError(t, err)
require.NotEmpty(t, v.Schema)
u, err := url.Parse(v.Schema)
require.NoError(t, err)
loader, ok := cmdext.States.Loader(u.Scheme)
require.True(t, ok)
drv, err := sqlclient.Open(ctx, "sqlite://test?mode=memory&_fk=1")
require.NoError(t, err)
sr, err := loader.LoadState(ctx, &cmdext.StateReaderConfig{
Dev: drv,
URLs: []*url.URL{u},
// Variables are not needed at this stage,
// as they are defined on the data source.
})
require.NoError(t, err)
require.Equal(t, "a8m", sr.Schema)
realm, err := sr.ReadState(ctx)
require.NoError(t, err)
buf, err := drv.MarshalSpec(realm)
require.NoError(t, err)
require.Equal(t, `table "t" {
schema = schema.a8m
column "c" {
null = false
type = int
}
}
schema "a8m" {
}
`, string(buf))
// An empty schema case.
err = os.WriteFile(filepath.Join(dir, "schema.hcl"), []byte(``), 0644)
require.NoError(t, err)
sr, err = loader.LoadState(ctx, &cmdext.StateReaderConfig{
Dev: drv,
URLs: []*url.URL{u},
// Variables are not needed at this stage,
// as they are defined on the data source.
})
require.NoError(t, err)
require.Empty(t, sr.Schema)
realm, err = sr.ReadState(ctx)
require.NoError(t, err)
buf, err = drv.MarshalSpec(realm)
require.NoError(t, err)
require.Equal(t, ``, string(buf))
}
func TestExternal(t *testing.T) {
var (
v struct {
Output string `spec:"output"`
}
state = schemahcl.New(cmdext.SpecOptions...)
)
err := state.EvalBytes([]byte(`
data "external" "program" {
program = [
"echo",
"value",
]
}
output = trimspace(data.external.program)
`), &v, nil)
require.NoError(t, err)
require.Equal(t, "value", v.Output)
err = state.EvalBytes([]byte(`
data "external" "program" {
program = [
"echo",
"{\"hello\": \"world\"}",
]
}
output = jsondecode(data.external.program).hello
`), &v, nil)
require.NoError(t, err)
require.Equal(t, "world", v.Output)
err = state.EvalBytes([]byte(`
variable "dot_env" {
type = string
}
data "external" "dot_env" {
program = [
"echo",
"${var.dot_env}",
]
}
locals {
dot_env = jsondecode(data.external.dot_env)
}
output = local.dot_env.URL
`), &v, map[string]cty.Value{
"dot_env": cty.StringVal(`{"URL": "https://example.com"}`),
})
require.NoError(t, err)
require.Equal(t, "https://example.com", v.Output)
}
// backupEnv backs up the current value of an environment variable
// and returns a function to restore it.
func backupEnv(keys ...string) (restoreFunc func()) {
backup := make(map[string]string, len(keys))
for _, key := range keys {
originalValue, exists := os.LookupEnv(key)
if exists {
backup[key] = originalValue
}
}
return func() {
for _, key := range keys {
if originalValue, exists := backup[key]; exists {
os.Setenv(key, originalValue)
} else {
os.Unsetenv(key)
}
}
}
}
================================================
FILE: cmd/atlas/internal/cmdext/reader.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdext
import (
"context"
"errors"
"fmt"
"io"
"net/url"
"os"
"path/filepath"
"strings"
cmdmigrate "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/schemahcl"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclparse"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"
)
type (
// StateReadCloser is a migrate.StateReader with an optional io.Closer.
StateReadCloser struct {
migrate.StateReader
io.Closer // optional close function
Schema string // in case we work on a single schema
HCL bool // true if state was read from HCL files since in that case we always compare realms
}
// StateReaderConfig is given to stateReader.
StateReaderConfig struct {
URLs []*url.URL // urls to create a migrate.StateReader from
Client, Dev *sqlclient.Client // database connections, while dev is considered a dev database, client is not
Schemas []string // schemas to work on
Exclude []string // exclude flag values
Include []string // include flag values
WithPos bool // Indicate if schema.Pos should be loaded.
Vars map[string]cty.Value
}
)
// Close redirects calls to Close to the enclosed io.Closer.
func (r *StateReadCloser) Close() error {
if r.Closer != nil {
return r.Closer.Close()
}
return nil
}
// isSchemaDir returns true if the given path is a schema directory (not a migration directory).
func isSchemaDir(u *url.URL, path string) bool {
if q := u.Query(); q.Has("version") || q.Has("format") || filepath.Base(path) == cmdmigrate.DefaultDirName {
return false
}
_, err := os.Stat(filepath.Join(path, migrate.HashFileName))
return errors.Is(err, os.ErrNotExist)
}
// errNoDevURL is returned when trying to read an SQL schema file/directory or replay a migration directory,
// the dev-url was not set.
var errNoDevURL = errors.New("--dev-url cannot be empty. See: https://atlasgo.io/atlas-schema/sql#dev-database")
// stateSchemaSQL wraps stateReaderSQL for SQL schema files or directories to control errors when replay/read fails.
func stateSchemaSQL(ctx context.Context, cfg *StateReaderConfig, dir migrate.Dir) (*StateReadCloser, error) {
if cfg.Dev == nil {
return nil, errNoDevURL
}
log := &errorRecorder{}
r, err := stateReaderSQL(ctx, cfg, dir, []migrate.ExecutorOption{migrate.WithLogger(log)}, nil)
if n := len(log.applied); err != nil && n > 0 && log.stmt != "" && log.text != "" {
err = fmt.Errorf("read state from %q: executing statement: %q: %s", log.applied[n-1], log.stmt, log.text)
}
return r, err
}
type errorRecorder struct {
applied []string // applied files.
stmt, text string // error statement and text.
}
// Log implements migrate.Logger.
func (r *errorRecorder) Log(e migrate.LogEntry) {
switch e := e.(type) {
case migrate.LogFile:
r.applied = append(r.applied, e.File.Name())
case migrate.LogError:
r.stmt = e.SQL
r.text = e.Error.Error()
}
}
// stateReaderSQL returns a migrate.StateReader from an SQL file or a directory of migrations.
func stateReaderSQL(ctx context.Context, cfg *StateReaderConfig, dir migrate.Dir, optsExec []migrate.ExecutorOption, optsReplay []migrate.ReplayOption) (*StateReadCloser, error) {
if cfg.Dev == nil {
return nil, errNoDevURL
}
ex, err := migrate.NewExecutor(cfg.Dev.Driver, dir, migrate.NopRevisionReadWriter{}, optsExec...)
if err != nil {
return nil, err
}
sr, err := ex.Replay(ctx, func() migrate.StateReader {
if cfg.Dev.URL.Schema != "" {
return migrate.SchemaConn(cfg.Dev, "", &schema.InspectOptions{
Exclude: cfg.Exclude,
Include: cfg.Include,
})
}
return migrate.RealmConn(cfg.Dev, &schema.InspectRealmOption{
Schemas: cfg.Schemas,
Exclude: cfg.Exclude,
Include: cfg.Include,
})
}(), optsReplay...)
if err != nil && !errors.Is(err, migrate.ErrNoPendingFiles) {
return nil, err
}
return &StateReadCloser{
StateReader: migrate.Realm(sr),
Schema: cfg.Dev.URL.Schema,
}, nil
}
// StateReaderHCL returns a StateReader that reads the state from the given HCL paths urls.
func StateReaderHCL(ctx context.Context, c *StateReaderConfig) (*StateReadCloser, error) {
paths := make([]string, len(c.URLs))
for i, u := range c.URLs {
paths[i] = filepath.Join(u.Host, u.Path)
}
return stateReaderHCL(ctx, c, paths)
}
// stateReaderHCL is shared between StateReaderHCL and "hcl_schema" datasource.
func stateReaderHCL(_ context.Context, config *StateReaderConfig, paths []string) (*StateReadCloser, error) {
var client *sqlclient.Client
switch {
case config.Dev != nil:
client = config.Dev
case config.Client != nil:
client = config.Client
default:
return nil, errors.New("--dev-url cannot be empty")
}
parser, err := parseHCLPaths(paths...)
if err != nil {
return nil, err
}
var (
eval = client.Eval
realm = &schema.Realm{}
)
if e, ok := client.Evaluator.(interface {
EvalOptions(*hclparse.Parser, any, *schemahcl.EvalOptions) error
}); ok && config.WithPos {
eval = func(pr *hclparse.Parser, v any, vars map[string]cty.Value) error {
return e.EvalOptions(pr, v, &schemahcl.EvalOptions{Variables: vars, RecordPos: true})
}
}
if err := eval(parser, realm, config.Vars); err != nil {
return nil, err
}
if len(config.Schemas) > 0 {
// Validate all schemas in file were selected by user.
sm := make(map[string]bool, len(config.Schemas))
for _, s := range config.Schemas {
sm[s] = true
}
for _, s := range realm.Schemas {
if !sm[s.Name] {
return nil, fmt.Errorf("schema %q from paths %q is not requested (all schemas in HCL must be requested)", s.Name, paths)
}
}
}
// In case the dev or client connection is bound to a specific schema, we require
// the desired schema to contain only one schema. Thus, executing diff will be
// done on the content of these two schema and not the whole realm.
switch {
case config.Dev != nil && config.Dev.URL.Schema != "" && len(realm.Schemas) > 1:
return nil, fmt.Errorf(
"cannot use HCL with more than 1 schema when dev-url is limited to schema %q",
config.Dev.URL.Schema,
)
case config.Client != nil && config.Client.URL.Schema != "" && len(realm.Schemas) > 1:
return nil, fmt.Errorf(
"cannot use HCL with more than 1 schema when url is limited to schema %q",
config.Client.URL.Schema,
)
}
var (
normalized bool
schemaScope string
)
// The "Schema" below indicates the HCL represents a single
// database schema, and the work is scoped to this schema.
if len(realm.Schemas) == 1 && (config.Dev != nil && config.Dev.URL.Schema != "" || config.Client != nil && config.Client.URL.Schema != "") {
schemaScope = realm.Schemas[0].Name
}
return &StateReadCloser{
HCL: true,
Schema: schemaScope,
// Defer normalization until the first call to ReadState. This is required because the same
// dev-database is used for both migration replaying and schema normalization. As a result,
// objects created by the migrations, which are not yet supported by Atlas, such as functions,
// won't be cleaned and can be referenced by the HCL schema.
StateReader: migrate.StateReaderFunc(func(ctx context.Context) (*schema.Realm, error) {
// Normalize once, only on dev database connection.
if nr, ok := client.Driver.(schema.Normalizer); ok && !normalized && config.Dev != nil {
switch {
// Empty schema file.
case len(realm.Schemas) == 0:
case config.Dev.URL.Schema != "":
realm.Schemas[0], err = nr.NormalizeSchema(ctx, realm.Schemas[0])
default:
realm, err = nr.NormalizeRealm(ctx, realm)
}
if err != nil {
return nil, err
}
}
if len(config.Include) > 0 {
switch {
case schemaScope != "" && len(realm.Schemas) == 1:
realm.Schemas[0], err = schema.IncludeSchema(realm.Schemas[0], config.Include)
default:
realm, err = schema.IncludeRealm(realm, config.Include)
}
if err != nil {
return nil, err
}
}
if len(config.Exclude) > 0 {
switch {
case schemaScope != "" && len(realm.Schemas) == 1:
realm.Schemas[0], err = schema.ExcludeSchema(realm.Schemas[0], config.Exclude)
default:
realm, err = schema.ExcludeRealm(realm, config.Exclude)
}
if err != nil {
return nil, err
}
}
return realm, nil
}),
}, nil
}
// FilesExt returns the file extension of the given URLs.
// Note, all URL must have the same extension.
func FilesExt(urls []*url.URL) (string, error) {
var path, ext string
set := func(curr string) error {
switch e := filepath.Ext(curr); {
case e != FileTypeHCL && e != FileTypeSQL:
return fmt.Errorf("unknown schema file: %q", curr)
case ext != "" && ext != e:
return fmt.Errorf("ambiguous schema: both SQL and HCL files found: %q, %q", path, curr)
default:
path, ext = curr, e
return nil
}
}
for _, u := range urls {
path := filepath.Join(u.Host, u.Path)
switch fi, err := os.Stat(path); {
case err != nil:
return "", err
case fi.IsDir():
files, err := os.ReadDir(path)
if err != nil {
return "", err
}
for _, f := range files {
switch filepath.Ext(f.Name()) {
// Ignore unknown extensions in case we read directories.
case FileTypeHCL, FileTypeSQL:
if err := set(f.Name()); err != nil {
return "", err
}
}
}
default:
if err := set(fi.Name()); err != nil {
return "", err
}
}
}
switch {
case ext != "":
case len(urls) == 1 && (urls[0].Host != "" || urls[0].Path != ""):
return "", fmt.Errorf(
"%q contains neither SQL nor HCL files",
filepath.Base(filepath.Join(urls[0].Host, urls[0].Path)),
)
default:
return "", errors.New("schema contains neither SQL nor HCL files")
}
return ext, nil
}
// parseHCLPaths parses the HCL files in the given paths. If a path represents a directory,
// its direct descendants will be considered, skipping any subdirectories. If a project file
// is present in the input paths, an error is returned.
func parseHCLPaths(paths ...string) (*hclparse.Parser, error) {
p := hclparse.NewParser()
for _, path := range paths {
switch stat, err := os.Stat(path); {
case err != nil:
return nil, err
case stat.IsDir():
dir, err := os.ReadDir(path)
if err != nil {
return nil, err
}
for _, f := range dir {
// Skip nested dirs.
if f.IsDir() {
continue
}
if err := mayParse(p, filepath.Join(path, f.Name())); err != nil {
return nil, err
}
}
default:
if err := mayParse(p, path); err != nil {
return nil, err
}
}
}
if len(p.Files()) == 0 {
return nil, fmt.Errorf("no schema files found in: %s", paths)
}
return p, nil
}
// Schema reader types (URL schemes).
const (
SchemaTypeFile = "file"
SchemaTypeAtlas = "atlas"
)
// File extensions supported by the file driver.
const (
FileTypeHCL = ".hcl"
FileTypeSQL = ".sql"
FileTypeTest = ".test.hcl"
)
// mayParse will parse the file in path if it is an HCL file. If the file is an Atlas
// project file an error is returned.
func mayParse(p *hclparse.Parser, path string) error {
if n := filepath.Base(path); filepath.Ext(n) != FileTypeHCL && !strings.HasSuffix(path, FileTypeTest) {
return nil
}
switch f, diag := p.ParseHCLFile(path); {
case diag.HasErrors():
return diag
case isProjectFile(f):
return fmt.Errorf("cannot parse project file %q as a schema file", path)
default:
return nil
}
}
func isProjectFile(f *hcl.File) bool {
for _, b := range f.Body.(*hclsyntax.Body).Blocks {
if b.Type == "env" {
return true
}
}
return false
}
// FilesAsDir wraps the given files as MemDir.
func FilesAsDir(files ...migrate.File) (migrate.Dir, error) {
dir := &migrate.MemDir{}
for _, f := range files {
if err := dir.WriteFile(f.Name(), f.Bytes()); err != nil {
return nil, err
}
}
// Create a checksum file to bypass the checksum check.
sum, err := dir.Checksum()
if err != nil {
return nil, err
}
if err = migrate.WriteSumFile(dir, sum); err != nil {
return nil, err
}
return dir, nil
}
================================================
FILE: cmd/atlas/internal/cmdext/reader_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdext
import (
"context"
"net/url"
"os"
"path/filepath"
"testing"
cmdmigrate "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
_ "ariga.io/atlas/sql/sqlite"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
)
func TestSchemaDirState(t *testing.T) {
ctx := context.Background()
dev, err := sqlclient.Open(ctx, "sqlite://dev?mode=memory")
require.NoError(t, err)
p1, p2 := filepath.Join(t.TempDir(), cmdmigrate.DefaultDirName), filepath.Join(t.TempDir(), "schema")
require.NoError(t, os.Mkdir(p1, 0755))
require.NoError(t, os.Mkdir(p2, 0755))
u1, err := url.Parse("file://" + p1)
require.NoError(t, err)
u2, err := url.Parse("file://" + p2)
require.NoError(t, err)
// Empty migration directory.
sr, err := StateReaderSQL(ctx, &StateReaderConfig{
Dev: dev,
URLs: []*url.URL{u1},
})
require.NoError(t, err)
r, err := sr.ReadState(ctx)
require.NoError(t, err)
require.Empty(t, r.Schemas[0].Tables, "empty main schema (default SQLite schema)")
// Sum file is required for migrations dir (named "migrations").
d1, err := migrate.NewLocalDir(p1)
require.NoError(t, err)
require.NoError(t, d1.WriteFile("1.sql", []byte("CREATE TABLE t1 (id INTEGER PRIMARY KEY);")))
_, err = StateReaderSQL(ctx, &StateReaderConfig{
Dev: dev,
URLs: []*url.URL{u1},
})
require.Error(t, err, "checksum file not found")
// Schema directory.
d2, err := migrate.NewLocalDir(p2)
require.NoError(t, err)
require.NoError(t, d2.WriteFile("1.sql", []byte("CREATE TABLE t1 (id INTEGER PRIMARY KEY);")))
sr, err = StateReaderSQL(ctx, &StateReaderConfig{
Dev: dev,
URLs: []*url.URL{u2},
})
require.NoError(t, err)
r, err = sr.ReadState(ctx)
require.NoError(t, err)
require.NotEmpty(t, r.Schemas[0].Tables, "non-empty schema")
// Exclude patterns.
sr, err = StateReaderSQL(ctx, &StateReaderConfig{
Dev: dev,
URLs: []*url.URL{u2},
Exclude: []string{"t1"},
})
require.NoError(t, err)
r, err = sr.ReadState(ctx)
require.NoError(t, err)
require.Empty(t, r.Schemas[0].Tables, "empty schema after excluding table")
// If schema contains a checksum file, it must be valid.
require.NoError(t, d2.WriteFile(migrate.HashFileName, []byte("invalid")))
_, err = StateReaderSQL(ctx, &StateReaderConfig{
Dev: dev,
URLs: []*url.URL{u2},
})
require.Error(t, err, "invalid checksum file")
}
func TestStateReaderHCL(t *testing.T) {
ctx := context.Background()
dev, err := sqlclient.Open(ctx, "sqlite://dev?mode=memory")
require.NoError(t, err)
p := filepath.Join(t.TempDir(), "schema")
require.NoError(t, os.Mkdir(p, 0755))
// Write an empty schema file into the directory.
require.NoError(t, os.WriteFile(p+"/schema.hcl", []byte(`
schema "default" {}
table "t1" {
schema = schema.default
column "id" {
type = int
}
column "name" {
type = text
}
}`), 0644))
// Read schema file.
u, err := url.Parse("file://" + p + "/schema.hcl")
sr, err := StateReaderHCL(ctx, &StateReaderConfig{
Dev: dev,
URLs: []*url.URL{u},
})
require.NoError(t, err)
r, err := sr.ReadState(ctx)
require.NoError(t, err)
require.Equal(t, schema.NewRealm().AddSchemas(
schema.New("default").AddTables(
schema.NewTable("t1").AddColumns(
schema.NewColumn("id").SetType(&schema.IntegerType{
T: "int",
}),
schema.NewColumn("name").SetType(&schema.StringType{
T: "text",
}),
),
),
), r)
// Read schema file with exclude patterns.
sr, err = StateReaderHCL(ctx, &StateReaderConfig{
Dev: dev,
URLs: []*url.URL{u},
Exclude: []string{"*.name"},
})
require.NoError(t, err)
r, err = sr.ReadState(ctx)
require.NoError(t, err)
_, exists := r.Schemas[0].Tables[0].Column("name")
require.False(t, exists, "column 'name' should be excluded")
// Mimic multi-schema file.
// Write an empty schema file into the directory.
require.NoError(t, os.WriteFile(p+"/schema.hcl", []byte(`
schema "main" {}
schema "default" {}
table "t1" {
schema = schema.default
column "id" {
type = int
}
column "name" {
type = text
}
}`), 0644))
sr, err = StateReaderHCL(ctx, &StateReaderConfig{
Dev: dev,
URLs: []*url.URL{u},
})
require.EqualError(t, err, `cannot use HCL with more than 1 schema when dev-url is limited to schema "main"`)
require.Nil(t, sr)
sr, err = StateReaderHCL(ctx, &StateReaderConfig{
Client: dev,
URLs: []*url.URL{u},
})
require.EqualError(t, err, `cannot use HCL with more than 1 schema when url is limited to schema "main"`)
require.Nil(t, sr)
}
================================================
FILE: cmd/atlas/internal/cmdlog/cmdlog.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdlog
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/url"
"reflect"
"slices"
"sort"
"strconv"
"strings"
"sync"
"text/template"
"time"
"ariga.io/atlas/cmd/atlas/internal/cmdext"
cmdmigrate "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
"github.com/fatih/color"
)
var (
ColorCyan = color.CyanString
ColorGray = color.New(color.Attribute(90))
ColorGreen = color.HiGreenString
ColorRed = color.HiRedString
ColorRedBgWhiteFg = color.New(color.FgHiWhite, color.BgHiRed).SprintFunc()
ColorYellow = color.YellowString
// ColorTemplateFuncs are globally available functions to color strings in a report template.
ColorTemplateFuncs = template.FuncMap{
"cyan": ColorCyan,
"green": ColorGreen,
"red": ColorRed,
"redBgWhiteFg": ColorRedBgWhiteFg,
"yellow": ColorYellow,
}
)
// WithColorFuncs extends the given template.FuncMap with the color functions.
func WithColorFuncs(f template.FuncMap) template.FuncMap {
for k, v := range ColorTemplateFuncs {
f[k] = v
}
return f
}
type (
// Env holds the environment information.
Env struct {
Driver string `json:"Driver,omitempty"` // Driver name.
URL *sqlclient.URL `json:"URL,omitempty"` // URL to dev database.
Dir string `json:"Dir,omitempty"` // Path to migration directory.
}
// Files is a slice of migrate.File. Implements json.Marshaler.
Files []migrate.File
// File wraps migrate.File to implement json.Marshaler.
File struct{ migrate.File }
// FileChecks represents a set of checks to run before applying a file.
FileChecks struct {
Name string `json:"Name,omitempty"` // File/group name.
Stmts []*Check `json:"Stmts,omitempty"` // Checks statements executed.
Error *StmtError `json:"Error,omitempty"` // Assertion error.
Start time.Time `json:"Start,omitempty"` // Start assertion time.
End time.Time `json:"End,omitempty"` // End assertion time.
}
// Check represents an assertion and its status.
Check struct {
Stmt string `json:"Stmt,omitempty"` // Assertion statement.
Error *string `json:"Error,omitempty"` // Assertion error, if any.
}
// StmtError groups a statement with its execution error.
StmtError struct {
Stmt string `json:"Stmt,omitempty"` // SQL statement that failed.
Text string `json:"Text,omitempty"` // Error message as returned by the database.
}
)
// MarshalJSON implements json.Marshaler.
func (f File) MarshalJSON() ([]byte, error) {
type local struct {
Name string `json:"Name,omitempty"`
Version string `json:"Version,omitempty"`
Description string `json:"Description,omitempty"`
}
return json.Marshal(local{f.Name(), f.Version(), f.Desc()})
}
// MarshalJSON implements json.Marshaler.
func (f Files) MarshalJSON() ([]byte, error) {
files := make([]File, len(f))
for i := range f {
files[i] = File{f[i]}
}
return json.Marshal(files)
}
// NewEnv returns an initialized Env.
func NewEnv(c *sqlclient.Client, dirURL *url.URL) Env {
e := Env{
Driver: c.Name,
URL: c.URL,
}
if dirURL != nil {
e.Dir = dirURL.Redacted()
}
return e
}
var (
// StatusTemplateFuncs are global functions available in status report templates.
StatusTemplateFuncs = WithColorFuncs(template.FuncMap{
"json": jsonEncode,
"json_merge": jsonMerge,
"default": func(report *MigrateStatus) (string, error) {
var buf bytes.Buffer
t, err := template.New("report").
Funcs(template.FuncMap{
"add": add,
}).
Funcs(ColorTemplateFuncs).
Parse(`Migration Status:
{{- if eq .Status "OK" }} {{ green .Status }}{{ end }}
{{- if eq .Status "PENDING" }} {{ yellow .Status }}{{ end }}
{{ yellow "--" }} Current Version: {{ cyan .Current }}
{{- if gt .Total 0 }}{{ printf " (%s statements applied)" (yellow "%d" .Count) }}{{ end }}
{{ yellow "--" }} Next Version: {{ if .Next }}{{ cyan .Next }}{{ if .FromCheckpoint }} (checkpoint){{ end }}{{ else }}UNKNOWN{{ end }}
{{- if gt .Total 0 }}{{ printf " (%s statements left)" (yellow "%d" .Left) }}{{ end }}
{{ yellow "--" }} Executed Files: {{ len .Applied }}{{ if gt .Total 0 }} (last one partially){{ end }}
{{ yellow "--" }} Pending Files: {{ add (len .Pending) (len .OutOfOrder) }}{{ if .OutOfOrder }} ({{ if .Pending }}{{ len .OutOfOrder }} {{ end }}out of order){{ end }}
{{- if gt .Total 0 }}
Last migration attempt had errors:
{{ yellow "--" }} SQL: {{ .SQL }}
{{ yellow "--" }} {{ red "ERROR:" }} {{ .Error }}
{{- else if and .OutOfOrder .Error }}
{{ red "ERROR:" }} {{ .Error }}
{{- end }}
`)
if err != nil {
return "", err
}
err = t.Execute(&buf, report)
return buf.String(), err
},
})
// MigrateStatusTemplate holds the default template of the 'migrate status' command.
MigrateStatusTemplate = template.Must(template.New("report").Funcs(StatusTemplateFuncs).Parse("{{ default . }}"))
)
// MigrateStatus contains a summary of the migration status of a database.
type MigrateStatus struct {
Env `json:"Env"`
Available Files `json:"Available,omitempty"` // Available migration files
OutOfOrder Files `json:"OutOfOrder,omitempty"` // OutOfOrder migration files
Pending Files `json:"Pending,omitempty"` // Pending migration files
Applied []*migrate.Revision `json:"Applied,omitempty"` // Applied migration files
Current string `json:"Current,omitempty"` // Current migration version
Next string `json:"Next,omitempty"` // Next migration version
Count int `json:"Count,omitempty"` // Count of applied statements of the last revision
Total int `json:"Total,omitempty"` // Total statements of the last migration
Status string `json:"Status,omitempty"` // Status of migration (OK, PENDING)
Error string `json:"Error,omitempty"` // Last Error that occurred
SQL string `json:"SQL,omitempty"` // SQL that caused the last Error
}
// Left returns the amount of statements left to apply (if any).
func (r *MigrateStatus) Left() int { return r.Total - r.Count }
// FromCheckpoint reports if we start from a checkpoint version
// Hence, the first file to be executed on the database is checkpoint.
func (r *MigrateStatus) FromCheckpoint() bool {
if len(r.Applied) > 0 || len(r.Pending) == 0 || r.Pending[0].Version() != r.Next {
return false
}
ck, ok := r.Pending[0].(migrate.CheckpointFile)
return ok && ck.IsCheckpoint()
}
// StatusReporter is used to gather information about migration status.
type StatusReporter struct {
// Client configures the connection to the database to file a MigrateStatus for.
Client *sqlclient.Client
// DirURL of the migration directory.
DirURL *url.URL
// Dir is used for scanning and validating the migration directory.
Dir migrate.Dir
// Schema name the revision table resides in.
Schema string
}
// Report creates and writes a MigrateStatus.
func (r *StatusReporter) Report(ctx context.Context) (*MigrateStatus, error) {
rep := &MigrateStatus{Env: NewEnv(r.Client, r.DirURL)}
// Check if there already is a revision table in the defined schema.
// Inspect schema and check if the table does already exist.
sch, err := r.Client.InspectSchema(ctx, r.Schema, &schema.InspectOptions{Tables: []string{revision.Table}})
if err != nil && !schema.IsNotExistError(err) {
return nil, err
}
if schema.IsNotExistError(err) || func() bool { _, ok := sch.Table(revision.Table); return !ok }() {
// Either schema or table does not exist.
if rep.Available, err = migrate.FilesFromLastCheckpoint(r.Dir); err != nil {
return nil, err
}
rep.Pending = rep.Available
} else {
// Both exist, fetch their data.
rrw, err := cmdmigrate.RevisionsForClient(ctx, r.Client, r.Schema)
if err != nil {
return nil, err
}
if err := rrw.Migrate(ctx); err != nil {
return nil, err
}
ex, err := migrate.NewExecutor(r.Client.Driver, r.Dir, rrw)
if err != nil {
return nil, err
}
rep.Applied, err = rrw.ReadRevisions(ctx)
if err != nil {
return nil, err
}
if rep.Pending, err = ex.Pending(ctx); err != nil && !errors.Is(err, migrate.ErrNoPendingFiles) {
if err1 := (*migrate.HistoryNonLinearError)(nil); errors.As(err, &err1) {
rep.Error = err1.Error()
rep.Status = statusPending
rep.Pending = err1.Pending
rep.OutOfOrder = err1.OutOfOrder
// Non-linear error means at least one file was applied.
rep.Current = rep.Applied[len(rep.Applied)-1].Version
return rep, nil
}
return nil, err
}
// If no files were applied, all pending files are
// available. The first one might be a checkpoint.
if len(rep.Applied) == 0 {
rep.Available = rep.Pending
} else if rep.Available, err = r.Dir.Files(); err != nil {
return nil, err
}
}
switch len(rep.Pending) {
case len(rep.Available):
rep.Current = "No migration applied yet"
default:
rep.Current = rep.Applied[len(rep.Applied)-1].Version
}
if len(rep.Pending) == 0 {
rep.Status = statusOK
rep.Next = "Already at latest version"
} else {
rep.Status = statusPending
rep.Next = rep.Pending[0].Version()
}
// If the last one is partially applied (and not manually resolved).
if len(rep.Applied) != 0 {
last := rep.Applied[len(rep.Applied)-1]
if !last.Type.Has(migrate.RevisionTypeResolved) && last.Applied < last.Total {
rep.SQL = strings.ReplaceAll(last.ErrorStmt, "\n", " ")
rep.Error = strings.ReplaceAll(last.Error, "\n", " ")
rep.Count = last.Applied
idx := migrate.FilesLastIndex(rep.Available, func(f migrate.File) bool {
return f.Version() == last.Version
})
if idx == -1 {
return nil, fmt.Errorf("migration file with version %q not found", last.Version)
}
stmts, err := migrate.FileStmts(r.Client.Driver, rep.Available[idx])
if err != nil {
return nil, err
}
rep.Total = len(stmts)
}
}
return rep, nil
}
const (
statusOK = "OK"
statusPending = "PENDING"
)
// MigrateSetTemplate holds the default template of the 'migrate set' command.
var MigrateSetTemplate = template.Must(template.New("set").
Funcs(ColorTemplateFuncs).Parse(`
{{- if and (not .Current) .Revisions -}}
All revisions deleted ({{ len .Revisions }} in total):
{{ else if and .Current .Revisions -}}
Current version is {{ cyan .Current.Version }} ({{ .Summary }}):
{{ end }}
{{- if .Revisions }}
{{ range .ByVersion }}
{{- $text := .ColoredVersion }}{{ with .Description }}{{ $text = printf "%s (%s)" $text . }}{{ end }}
{{- printf " %s\n" $text }}
{{- end }}
{{ end -}}
`))
type (
// MigrateSet contains a summary of the migrate set command.
MigrateSet struct {
ctx context.Context
// Revisions that were added, removed or updated.
Revisions []RevisionOp `json:"Revisions,omitempty"`
// Current version in the revisions table.
Current *migrate.Revision `json:"Latest,omitempty"`
}
// RevisionOp represents an operation done on a revision.
RevisionOp struct {
*migrate.Revision
Op string `json:"Op,omitempty"`
}
)
// NewMigrateSet returns a MigrateSet.
func NewMigrateSet(ctx context.Context) *MigrateSet {
return &MigrateSet{ctx: ctx}
}
// ByVersion returns all revisions sorted by version.
func (r *MigrateSet) ByVersion() []RevisionOp {
sort.Slice(r.Revisions, func(i, j int) bool {
return r.Revisions[i].Version < r.Revisions[j].Version
})
return r.Revisions
}
// Set records revision that was added.
func (r *MigrateSet) Set(rev *migrate.Revision) {
r.Revisions = append(r.Revisions, RevisionOp{Revision: rev, Op: "set"})
}
// Removed records revision that was added.
func (r *MigrateSet) Removed(rev *migrate.Revision) {
r.Revisions = append(r.Revisions, RevisionOp{Revision: rev, Op: "remove"})
}
// Summary returns a summary of the set operation.
func (r *MigrateSet) Summary() string {
var s, d int
for i := range r.Revisions {
switch r.Revisions[i].Op {
case "set":
s++
default:
d++
}
}
var sum []string
if s > 0 {
sum = append(sum, fmt.Sprintf("%d set", s))
}
if d > 0 {
sum = append(sum, fmt.Sprintf("%d removed", d))
}
return strings.Join(sum, ", ")
}
// ColoredVersion returns the version of the revision with a color.
func (r *RevisionOp) ColoredVersion() string {
c := color.HiGreenString("+")
if r.Op != "set" {
c = color.HiRedString("-")
}
return c + " " + r.Version
}
var (
// ApplyTemplateFuncs are global functions available in apply report templates.
ApplyTemplateFuncs = WithColorFuncs(template.FuncMap{
"add": add,
"upper": strings.ToUpper,
"json": jsonEncode,
"json_merge": jsonMerge,
"indent_ln": indentLn,
})
// MigrateApplyTemplate holds the default template of the 'migrate apply' command.
MigrateApplyTemplate = template.Must(template.
New("report").
Funcs(ApplyTemplateFuncs).
Parse(`{{- if not .Pending -}}
{{- println "No migration files to execute" }}
{{- else -}}
{{- println .Header }}
{{- range $i, $f := .Applied }}
{{- println }}
{{- $checkFailed := false }}
{{- range $cf := $f.Checks }}
{{- println " " (yellow "--") "checks before migrating version" (cyan $f.File.Version) }}
{{- range $s := $cf.Stmts }}
{{- if $s.Error }}
{{- println " " (red "->") (indent_ln $s.Stmt 7) }}
{{- else }}
{{- println " " (cyan "->") (indent_ln $s.Stmt 7) }}
{{- end }}
{{- end }}
{{- with $cf.Error }}
{{- $checkFailed = true }}
{{- println " " (redBgWhiteFg .Text) }}
{{- else }}
{{- printf " %s ok (%s)\n\n" (yellow "--") (yellow ($cf.End.Sub $cf.Start).String) }}
{{- end }}
{{- end }}
{{- if $checkFailed }}
{{- continue }} {{- /* No statements were applied. */}}
{{- end }}
{{- println " " (yellow "--") "migrating version" (cyan $f.File.Version) }}
{{- range $f.Applied }}
{{- println " " (cyan "->") (indent_ln . 7) }}
{{- end }}
{{- with .Error }}
{{- println " " (redBgWhiteFg .Text) }}
{{- else }}
{{- printf " %s ok (%s)\n" (yellow "--") (yellow (.End.Sub .Start).String) }}
{{- end }}
{{- else }}
{{- println }}
{{- with .Error }}
{{- println " " (redBgWhiteFg .) }}
{{- end }}
{{- end }}
{{- println }}
{{- println " " (cyan "-------------------------") }}
{{- println " " (.Summary " ") }}
{{- end -}}
`))
)
type (
// MigrateApply contains a summary of a migration applying attempt on a database.
MigrateApply struct {
ctx context.Context
Env
Pending Files `json:"Pending,omitempty"` // Pending migration files
Applied []*AppliedFile `json:"Applied,omitempty"` // Applied files
Current string `json:"Current,omitempty"` // Current migration version
Target string `json:"Target,omitempty"` // Target migration version
Start time.Time
End time.Time
// Error is set even then, if it was not caused by a statement in a migration file,
// but by Atlas, e.g. when committing or rolling back a transaction.
Error string `json:"Error,omitempty"`
}
// AppliedFile is part of an MigrateApply containing information about an applied file in a migration attempt.
AppliedFile struct {
migrate.File
Start time.Time
End time.Time
Skipped int // Amount of skipped SQL statements in a partially applied file.
Applied []string // SQL statements applied with success
Checks []*FileChecks // Assertion checks
Error *StmtError
}
)
// NewMigrateApply returns an MigrateApply.
func NewMigrateApply(ctx context.Context, client *sqlclient.Client, dirURL *url.URL) *MigrateApply {
return &MigrateApply{
ctx: ctx,
Env: NewEnv(client, dirURL),
Start: time.Now(),
}
}
// Log implements migrate.Logger.
func (a *MigrateApply) Log(e migrate.LogEntry) {
switch e := e.(type) {
case migrate.LogExecution:
// Do not set start time if it
// was set by the constructor.
if a.Start.IsZero() {
a.Start = time.Now()
}
a.Current = e.From
a.Target = e.To
a.Pending = e.Files
case migrate.LogFile:
if l := len(a.Applied); l > 0 {
f := a.Applied[l-1]
f.End = time.Now()
}
a.Applied = append(a.Applied, &AppliedFile{
File: File{e.File},
Start: time.Now(),
Skipped: e.Skip,
})
case migrate.LogChecks:
f := a.Applied[len(a.Applied)-1]
f.Checks = append(f.Checks, &FileChecks{
Name: e.Name,
Start: time.Now(),
Stmts: make([]*Check, 0, len(e.Stmts)),
})
case migrate.LogCheck:
var (
f = a.Applied[len(a.Applied)-1]
cf = f.Checks[len(f.Checks)-1]
ck = &Check{Stmt: a.MaskedText(e.Decl)}
)
if e.Error != nil {
m := a.MaskedErrorText(migrate.LogError{
Error: e.Error,
Stmt: e.Decl,
})
ck.Error = &m
}
cf.Stmts = append(cf.Stmts, ck)
case migrate.LogChecksDone:
f := a.Applied[len(a.Applied)-1]
cf := f.Checks[len(f.Checks)-1]
cf.End = time.Now()
if e.Error != nil {
cf.Error = &StmtError{
Text: e.Error.Error(),
Stmt: cf.Stmts[len(cf.Stmts)-1].Stmt,
}
}
case migrate.LogStmt:
f := a.Applied[len(a.Applied)-1]
f.Applied = append(f.Applied, a.MaskedText(e.Stmt))
case migrate.LogError:
// Error during migration.
if l := len(a.Applied); l > 0 {
f := a.Applied[len(a.Applied)-1]
f.End = time.Now()
a.End = f.End
switch {
case e.Stmt != nil:
f.Error = &StmtError{
Stmt: a.MaskedText(e.Stmt),
Text: a.MaskedErrorText(e),
}
default:
f.Error = &StmtError{Stmt: e.SQL, Text: e.Error.Error()}
}
// Error during pre stages, such as
// scanning migration statements.
} else {
a.End = time.Now()
a.Error = a.MaskedErrorText(e)
}
case migrate.LogDone:
n := time.Now()
if l := len(a.Applied); l > 0 {
a.Applied[l-1].End = n
}
a.End = n
}
}
// Header returns a header of the migration log.
func (a *MigrateApply) Header() string {
if len(a.Pending) == 0 {
return "No migration files to execute"
}
var b strings.Builder
b.WriteString("Migrating to version ")
b.WriteString(ColorCyan(a.Target))
if a.Current != "" {
b.WriteString(" from ")
b.WriteString(ColorCyan(a.Current))
}
b.WriteString(" (")
b.WriteString(strconv.Itoa(len(a.Pending)))
b.WriteString(" migrations in total):")
return b.String()
}
// Summary returns a footer of the migration log.
func (a *MigrateApply) Summary(ident string) string {
var (
passedC, failedC int
passedS, failedS int
passedF, failedF int
lines = make([]string, 0, 3)
)
for _, f := range a.Applied {
// For each check file, count the
// number of failed assertions.
for _, cf := range f.Checks {
for _, s := range cf.Stmts {
if s.Error != nil {
failedC++
} else {
passedC++
}
}
}
passedS += len(f.Applied)
if f.Error != nil {
failedF++
// Last statement failed (not an assertion).
if len(f.Checks) == 0 || f.Checks[len(f.Checks)-1].Error == nil {
passedS--
failedS++
}
} else {
passedF++
}
}
// Execution time.
lines = append(lines, a.End.Sub(a.Start).String())
// Executed files.
switch {
case passedF > 0 && failedF > 0:
lines = append(lines, fmt.Sprintf("%d migration%s ok, %d with errors", passedF, plural(passedF), failedF))
case passedF > 0:
lines = append(lines, fmt.Sprintf("%d migration%s", passedF, plural(passedF)))
case failedF > 0:
lines = append(lines, fmt.Sprintf("%d migration%s with errors", failedF, plural(failedF)))
}
// Executed checks.
switch {
case passedC > 0 && failedC > 0:
lines = append(lines, fmt.Sprintf("%d check%s ok, %d failure%s", passedC, plural(passedC), failedC, plural(failedC)))
case passedC > 0:
lines = append(lines, fmt.Sprintf("%d check%s", passedC, plural(passedC)))
case failedC > 0:
lines = append(lines, fmt.Sprintf("%d check error%s", failedC, plural(failedC)))
}
// Executed statements.
switch {
case passedS > 0 && failedS > 0:
lines = append(lines, fmt.Sprintf("%d sql statement%s ok, %d with errors", passedS, plural(passedS), failedS))
case passedS > 0:
lines = append(lines, fmt.Sprintf("%d sql statement%s", passedS, plural(passedS)))
case failedS > 0:
lines = append(lines, fmt.Sprintf("%d sql statement%s with errors", failedS, plural(failedS)))
}
var b strings.Builder
for i, l := range lines {
b.WriteString(ColorYellow("--"))
b.WriteByte(' ')
b.WriteString(l)
if i < len(lines)-1 {
b.WriteByte('\n')
b.WriteString(ident)
}
}
return b.String()
}
func plural(n int) (s string) {
if n > 1 {
s += "s"
}
return
}
// MarshalJSON implements json.Marshaler.
func (a *MigrateApply) MarshalJSON() ([]byte, error) {
type Alias MigrateApply
var v struct {
*Alias
Message string `json:"Message,omitempty"`
}
v.Alias = (*Alias)(a)
switch {
case a.Error != "":
case len(v.Applied) == 0:
v.Message = "No migration files to execute"
default:
v.Message = fmt.Sprintf("Migrated to version %s from %s (%d migrations in total)", v.Target, v.Current, len(v.Pending))
}
return json.Marshal(v)
}
// MarshalJSON implements json.Marshaler.
func (f *AppliedFile) MarshalJSON() ([]byte, error) {
type local struct {
Name string `json:"Name,omitempty"`
Version string `json:"Version,omitempty"`
Description string `json:"Description,omitempty"`
Start time.Time `json:"Start,omitempty"`
End time.Time `json:"End,omitempty"`
Skipped int `json:"Skipped,omitempty"`
Stmts []string `json:"Applied,omitempty"`
Error *StmtError `json:"Error,omitempty"`
}
return json.Marshal(local{
Name: f.Name(),
Version: f.Version(),
Description: f.Desc(),
Start: f.Start,
End: f.End,
Skipped: f.Skipped,
Stmts: f.Applied,
Error: f.Error,
})
}
// SchemaPlanTemplate holds the default template of the 'schema apply --dry-run' command.
var SchemaPlanTemplate = template.Must(template.
New("plan").
Funcs(ApplyTemplateFuncs).
Parse(`{{- with .Changes.Pending -}}
-- Planned Changes:
{{ range . -}}
{{- if .Comment -}}
{{- printf "-- %s%s\n" (slice .Comment 0 1 | upper ) (slice .Comment 1) -}}
{{- end -}}
{{- printf "%s;\n" .Cmd -}}
{{- end -}}
{{- else -}}
Schema is synced, no changes to be made
{{ end -}}
`))
// Changes represents a list of changes that are pending or applied.
type Changes struct {
Applied []*migrate.Change `json:"Applied,omitempty"` // SQL changes applied with success
Pending []*migrate.Change `json:"Pending,omitempty"` // SQL changes that were not applied
Error *StmtError `json:"Error,omitempty"` // Error that occurred during applying
}
// MarshalJSON implements json.Marshaler.
func (c Changes) MarshalJSON() ([]byte, error) {
var v struct {
Applied []string `json:"Applied,omitempty"`
Pending []string `json:"Pending,omitempty"`
Error *StmtError `json:"Error,omitempty"`
}
for i := range c.Applied {
v.Applied = append(v.Applied, c.Applied[i].Cmd)
}
for i := range c.Pending {
v.Pending = append(v.Pending, c.Pending[i].Cmd)
}
v.Error = c.Error
return json.Marshal(v)
}
// SchemaInspect contains a summary of the 'schema inspect' command.
type SchemaInspect struct {
ctx context.Context
client *sqlclient.Client
URL string `json:"-"` // Target URL to inspect, my contain sensitive information.
Realm *schema.Realm `json:"Schema,omitempty"` // Inspected realm.
}
var (
// InspectTemplateFuncs are global functions available in inspect report templates.
InspectTemplateFuncs = template.FuncMap{
"base64url": base64url,
"sql": sqlInspect,
"json": jsonEncode,
"mermaid": mermaid,
"split": func(...any) (string, error) {
return "", cmdext.UnsupportedErr("\n'atlas schema inspect' with 'split' function")
},
"write": func(...any) (string, error) {
return "", cmdext.UnsupportedErr("\n'atlas schema inspect' with 'write' function")
},
"hcl": func(...any) (string, error) {
return "", cmdext.UnsupportedErr("\n'atlas schema inspect' with 'hcl' function")
},
}
// SchemaInspectTemplate holds the default template of the 'schema inspect' command.
SchemaInspectTemplate = template.Must(template.New("inspect").
Funcs(InspectTemplateFuncs).
Parse(`{{ $.MarshalHCL }}`))
)
// NewSchemaInspect returns a SchemaInspect.
func NewSchemaInspect(ctx context.Context, client *sqlclient.Client, realm *schema.Realm) *SchemaInspect {
return &SchemaInspect{ctx: ctx, client: client, Realm: realm}
}
// Client returns the client used to inspect the schema.
func (s *SchemaInspect) Client() *sqlclient.Client {
return s.client
}
// MarshalHCL returns the default HCL representation of the schema.
// Used by the template declared above.
func (s *SchemaInspect) MarshalHCL() (string, error) {
spec, err := s.client.MarshalSpec(s.Realm)
if err != nil {
return "", err
}
return string(spec), nil
}
// RedactedURL returns the inspected url redacted.
func (s *SchemaInspect) RedactedURL() (string, error) {
u, err := url.Parse(s.URL)
if err != nil {
return "", err
}
return u.Redacted(), nil
}
// MarshalJSON implements json.Marshaler.
func (s *SchemaInspect) MarshalJSON() ([]byte, error) {
type (
Attrs struct {
Comment string `json:"comment,omitempty"`
Charset string `json:"charset,omitempty"`
Collate string `json:"collate,omitempty"`
}
Column struct {
Name string `json:"name"`
Type string `json:"type,omitempty"`
Null bool `json:"null,omitempty"`
Attrs
}
IndexPart struct {
Desc bool `json:"desc,omitempty"`
Column string `json:"column,omitempty"`
Expr string `json:"expr,omitempty"`
}
Index struct {
Name string `json:"name,omitempty"`
Unique bool `json:"unique,omitempty"`
Parts []IndexPart `json:"parts,omitempty"`
}
ForeignKey struct {
Name string `json:"name"`
Columns []string `json:"columns,omitempty"`
References struct {
Table string `json:"table"`
Columns []string `json:"columns,omitempty"`
} `json:"references"`
}
Table struct {
Name string `json:"name"`
Columns []Column `json:"columns,omitempty"`
Indexes []Index `json:"indexes,omitempty"`
PrimaryKey *Index `json:"primary_key,omitempty"`
ForeignKeys []ForeignKey `json:"foreign_keys,omitempty"`
Attrs
}
Schema struct {
Name string `json:"name"`
Tables []Table `json:"tables,omitempty"`
Attrs
}
)
var (
realm struct {
Schemas []Schema `json:"schemas,omitempty"`
}
setAttrs = func(from []schema.Attr, to *Attrs) {
for i := range from {
switch a := from[i].(type) {
case *schema.Comment:
to.Comment = a.Text
case *schema.Charset:
to.Charset = a.V
case *schema.Collation:
to.Collate = a.V
}
}
}
)
for _, s1 := range s.Realm.Schemas {
s2 := Schema{Name: s1.Name}
setAttrs(s1.Attrs, &s2.Attrs)
for _, t1 := range s1.Tables {
t2 := Table{Name: t1.Name}
setAttrs(t1.Attrs, &t2.Attrs)
for _, c1 := range t1.Columns {
c2 := Column{
Name: c1.Name,
Type: c1.Type.Raw,
Null: c1.Type.Null,
}
setAttrs(c1.Attrs, &c2.Attrs)
t2.Columns = append(t2.Columns, c2)
}
idxParts := func(idx *schema.Index) (parts []IndexPart) {
for _, p1 := range idx.Parts {
p2 := IndexPart{Desc: p1.Desc}
switch {
case p1.C != nil:
p2.Column = p1.C.Name
case p1.X != nil:
switch t := p1.X.(type) {
case *schema.Literal:
p2.Expr = t.V
case *schema.RawExpr:
p2.Expr = t.X
}
}
parts = append(parts, p2)
}
return parts
}
for _, idx1 := range t1.Indexes {
t2.Indexes = append(t2.Indexes, Index{
Name: idx1.Name,
Unique: idx1.Unique,
Parts: idxParts(idx1),
})
}
if t1.PrimaryKey != nil {
t2.PrimaryKey = &Index{Parts: idxParts(t1.PrimaryKey)}
}
for _, fk1 := range t1.ForeignKeys {
fk2 := ForeignKey{Name: fk1.Symbol}
for _, c1 := range fk1.Columns {
fk2.Columns = append(fk2.Columns, c1.Name)
}
fk2.References.Table = fk1.RefTable.Name
for _, c1 := range fk1.RefColumns {
fk2.References.Columns = append(fk2.References.Columns, c1.Name)
}
t2.ForeignKeys = append(t2.ForeignKeys, fk2)
}
s2.Tables = append(s2.Tables, t2)
}
realm.Schemas = append(realm.Schemas, s2)
}
return json.Marshal(realm)
}
// MarshalSQL returns the default SQL representation of the schema.
func (s *SchemaInspect) MarshalSQL(indent ...string) (string, error) {
return sqlInspect(s, indent...)
}
func sqlInspect(report *SchemaInspect, indent ...string) (string, error) {
return fmtPlan(report.ctx, report.client, cmdmigrate.ChangesToRealm(report.client, report.Realm), indent)
}
// base64url assumes the input is a base64 encoded string and
// replaces characters to make it URL safe.
func base64url(s string) string {
return strings.NewReplacer("+", "-", "/", "_", "=", "").Replace(s)
}
// SchemaDiff contains a summary of the 'schema diff' command.
type SchemaDiff struct {
ctx context.Context
client *sqlclient.Client
From, To *schema.Realm
Changes []schema.Change
}
var (
// SchemaDiffFuncs are global functions available in diff report templates.
SchemaDiffFuncs = template.FuncMap{
"sql": sqlDiff,
}
// SchemaDiffTemplate holds the default template of the 'schema diff' command.
SchemaDiffTemplate = template.Must(template.
New("schema_diff").
Funcs(SchemaDiffFuncs).
Parse(`{{- with .Changes -}}
{{ sql $ }}
{{- else -}}
Schemas are synced, no changes to be made.
{{ end -}}
`))
)
// NewSchemaDiff returns a SchemaDiff.
func NewSchemaDiff(ctx context.Context, client *sqlclient.Client, from, to *schema.Realm, changes []schema.Change) *SchemaDiff {
return &SchemaDiff{
ctx: ctx,
client: client,
From: from,
To: to,
Changes: changes,
}
}
// Client returns the client used to inspect the schema.
func (s *SchemaDiff) Client() *sqlclient.Client { return s.client }
// MarshalSQL returns the default SQL representation of the schema.
func (s *SchemaDiff) MarshalSQL(indent ...string) (string, error) {
return sqlDiff(s, indent...)
}
func sqlDiff(diff *SchemaDiff, indent ...string) (string, error) {
return fmtPlan(diff.ctx, diff.client, diff.Changes, indent)
}
func fmtPlan(ctx context.Context, client *sqlclient.Client, changes schema.Changes, indent []string, edit ...func(*migrate.Plan)) (string, error) {
if len(indent) > 1 {
return "", fmt.Errorf("unexpected number of arguments: %d", len(indent))
}
plan, err := client.PlanChanges(ctx, "plan", changes, func(o *migrate.PlanOptions) {
o.Mode = migrate.PlanModeDump
// Disable object qualifier in schema-mode.
if client.URL.Schema != "" {
o.SchemaQualifier = new(string)
}
if len(indent) > 0 {
o.Indent = indent[0]
}
})
if err != nil {
return "", err
}
// Optional edit functions.
for i := range edit {
edit[i](plan)
}
f, err := migrate.DefaultFormatter.FormatFile(plan)
if err != nil {
return "", err
}
return string(f.Bytes()), nil
}
func mermaid(i *SchemaInspect, _ ...string) (string, error) {
ft, ok := i.client.Driver.(interface {
FormatType(schema.Type) (string, error)
})
if !ok {
return "", fmt.Errorf("mermaid: driver does not support FormatType")
}
var (
b strings.Builder
qualify = len(i.Realm.Schemas) > 1
funcs = template.FuncMap{
"nospace": strings.NewReplacer(" ", "_").Replace,
"formatType": ft.FormatType,
"tableName": func(t *schema.Table) string {
if qualify {
return fmt.Sprintf("%[1]s_%[2]s[\"%[1]s.%[2]s\"]", t.Schema.Name, t.Name)
}
return t.Name
},
"tableIdent": func(t *schema.Table) string {
if qualify {
return fmt.Sprintf("%s_%s", t.Schema.Name, t.Name)
}
return t.Name
},
"pkfk": func(t *schema.Table, c *schema.Column) string {
var pkfk []string
if t.PrimaryKey != nil && slices.ContainsFunc(t.PrimaryKey.Parts, func(p *schema.IndexPart) bool { return p.C == c }) {
pkfk = append(pkfk, "PK")
}
if c.ForeignKeys != nil {
pkfk = append(pkfk, "FK")
}
return strings.Join(pkfk, ",")
},
"card": func(fk *schema.ForeignKey) string {
var (
hasU = func(t *schema.Table, cs []*schema.Column) bool {
if t.PrimaryKey != nil && slices.EqualFunc(t.PrimaryKey.Parts, cs, func(p *schema.IndexPart, c *schema.Column) bool {
return p.C != nil && p.C.Name == c.Name
}) {
return true
}
return slices.ContainsFunc(t.Indexes, func(idx *schema.Index) bool {
return idx.Unique && slices.EqualFunc(idx.Parts, cs, func(p *schema.IndexPart, c *schema.Column) bool {
return p.C != nil && p.C.Name == c.Name
})
})
}
from, to = "}", "{"
)
if hasU(fk.Table, fk.Columns) {
from = "|"
}
if hasU(fk.RefTable, fk.RefColumns) {
to = "|"
}
return fmt.Sprintf("%so--o%s", from, to)
},
}
t = template.Must(template.New("mermaid").
Funcs(funcs).
Parse(`erDiagram
{{- range $s := .Schemas }}
{{- range $t := $s.Tables }}
{{ tableName $t }} {
{{- range $c := $t.Columns }}
{{ formatType $c.Type.Type | nospace }} {{ nospace $c.Name }}{{ with pkfk $t $c }} {{ . }}{{ end }}
{{- end }}
}
{{- range $fk := $t.ForeignKeys }}
{{ tableIdent $t }} {{ card $fk }} {{ tableIdent $fk.RefTable }} : {{ $fk.Symbol }}
{{- end }}
{{- end }}
{{- end }}
`))
)
if err := t.Execute(&b, i.Realm); err != nil {
return "", err
}
return b.String(), nil
}
func jsonEncode(v any, args ...string) (string, error) {
var (
b []byte
err error
)
switch len(args) {
case 0:
b, err = json.Marshal(v)
case 1:
b, err = json.MarshalIndent(v, "", args[0])
default:
b, err = json.MarshalIndent(v, args[0], args[1])
}
return string(b), err
}
func jsonMerge(objects ...string) (string, error) {
var r map[string]any
for i := range objects {
if err := json.Unmarshal([]byte(objects[i]), &r); err != nil {
return "", fmt.Errorf("json_merge: %w", err)
}
}
b, err := json.Marshal(r)
if err != nil {
return "", fmt.Errorf("json_merge: %w", err)
}
return string(b), nil
}
func add(a, b int) int {
return a + b
}
func indentLn(input string, indent int) string {
pad := strings.Repeat(" ", indent)
return strings.ReplaceAll(input, "\n", "\n"+pad)
}
// noDirectives returns a slice of comments without directives.
func noDirectives(comments []string) (cs []string) {
for _, c := range comments {
if !strings.HasPrefix(c, "-- atlas:") {
cs = append(cs, c)
}
}
return cs
}
// WarnOnce allow writing warning messages to the given writer,
// but ensures only one message will be written in process run.
func WarnOnce(w io.Writer, text string) error {
if !reflect.TypeOf(w).Comparable() {
_, err := w.Write([]byte(text))
return err
}
if _, loaded := oneWrites.LoadOrStore(w, true); !loaded {
_, err := w.Write([]byte(text))
return err
}
return nil
}
// oneWrites per writer.
var oneWrites sync.Map
================================================
FILE: cmd/atlas/internal/cmdlog/cmdlog_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package cmdlog
import (
"context"
"ariga.io/atlas/sql/migrate"
)
// SchemaApply contains a summary of a 'schema apply' execution on a database.
type SchemaApply struct {
ctx context.Context `json:"-"`
Env
Changes Changes `json:"Changes,omitempty"`
// General error that occurred during execution.
// e.g., when committing or rolling back a transaction.
Error string `json:"Error,omitempty"`
}
// NewSchemaApply returns a SchemaApply.
func NewSchemaApply(ctx context.Context, env Env, applied, pending []*migrate.Change, err *StmtError) *SchemaApply {
return &SchemaApply{
ctx: ctx,
Env: env,
Changes: Changes{
Applied: applied,
Pending: pending,
Error: err,
},
}
}
// NewSchemaPlan returns a SchemaApply only with pending changes.
func NewSchemaPlan(ctx context.Context, env Env, pending []*migrate.Change, err *StmtError) *SchemaApply {
return NewSchemaApply(ctx, env, nil, pending, err)
}
func (*MigrateApply) MaskedText(s *migrate.Stmt) string {
return s.Text // Unsupported feature.
}
// MaskedErrorText returns the masked versioned of the error, if caused by a statement.
func (*MigrateApply) MaskedErrorText(e migrate.LogError) string {
return e.Error.Error() // Unsupported feature.
}
================================================
FILE: cmd/atlas/internal/cmdlog/cmdlog_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdlog_test
import (
"bytes"
"context"
"encoding/json"
"io"
"path/filepath"
"strings"
"sync"
"testing"
"text/template"
"time"
cmdmigrate "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/cmd/atlas/internal/cmdlog"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
_ "ariga.io/atlas/sql/sqlite"
"github.com/fatih/color"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
)
func TestSchemaInspect_MarshalJSON(t *testing.T) {
report := &cmdlog.SchemaInspect{
Realm: schema.NewRealm(
schema.New("test").
SetComment("schema comment").
AddTables(
schema.NewTable("users").
SetCharset("charset").
AddColumns(
&schema.Column{
Name: "id",
Type: &schema.ColumnType{Raw: "bigint"},
},
&schema.Column{
Name: "name",
Type: &schema.ColumnType{Raw: "varchar(255)"},
Attrs: []schema.Attr{
&schema.Collation{V: "collate"},
},
},
),
schema.NewTable("posts").
AddColumns(
&schema.Column{
Name: "id",
Type: &schema.ColumnType{Raw: "bigint"},
},
&schema.Column{
Name: "text",
Type: &schema.ColumnType{Raw: "text"},
},
),
),
schema.New("temp"),
),
}
b, err := report.MarshalJSON()
require.NoError(t, err)
ident, err := json.MarshalIndent(json.RawMessage(b), "", " ")
require.NoError(t, err)
require.Equal(t, `{
"schemas": [
{
"name": "test",
"tables": [
{
"name": "users",
"columns": [
{
"name": "id",
"type": "bigint"
},
{
"name": "name",
"type": "varchar(255)",
"collate": "collate"
}
],
"charset": "charset"
},
{
"name": "posts",
"columns": [
{
"name": "id",
"type": "bigint"
},
{
"name": "text",
"type": "text"
}
]
}
],
"comment": "schema comment"
},
{
"name": "temp"
}
]
}`, string(ident))
}
func TestSchemaInspect_MarshalSQL(t *testing.T) {
client, err := sqlclient.Open(context.Background(), "sqlite://ci?mode=memory&_fk=1")
require.NoError(t, err)
defer client.Close()
report := cmdlog.NewSchemaInspect(
context.Background(),
client,
schema.NewRealm(
schema.New("main").
AddTables(
schema.NewTable("users").
AddColumns(
schema.NewIntColumn("id", "int"),
),
),
),
)
b, err := report.MarshalSQL()
require.NoError(t, err)
require.Equal(t, "-- Create \"users\" table\nCREATE TABLE `users` (`id` int NOT NULL);\n", b)
}
func TestSchemaInspect_EncodeSQL(t *testing.T) {
ctx := context.Background()
client, err := sqlclient.Open(ctx, "sqlite://ci?mode=memory&_fk=1")
require.NoError(t, err)
defer client.Close()
err = client.ApplyChanges(ctx, schema.Changes{
&schema.AddTable{
T: schema.NewTable("users").
AddColumns(
schema.NewIntColumn("id", "int"),
schema.NewStringColumn("name", "text"),
),
},
})
require.NoError(t, err)
realm, err := client.InspectRealm(ctx, nil)
require.NoError(t, err)
var (
b bytes.Buffer
tmpl = template.Must(template.New("format").Funcs(cmdlog.InspectTemplateFuncs).Parse(`{{ sql . }}`))
)
require.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(ctx, client, realm)))
require.Equal(t, "-- Create \"users\" table\nCREATE TABLE `users` (`id` int NOT NULL, `name` text NOT NULL);\n", b.String())
}
func TestSchemaInspect_Mermaid(t *testing.T) {
ctx := context.Background()
client, err := sqlclient.Open(ctx, "sqlite://ci?mode=memory&_fk=1")
require.NoError(t, err)
defer client.Close()
var (
b bytes.Buffer
users = schema.NewTable("users").
AddColumns(
schema.NewIntColumn("id", "int"),
schema.NewStringColumn("name", "text"),
)
tmpl = template.Must(template.New("format").Funcs(cmdlog.InspectTemplateFuncs).Parse(`{{ mermaid . }}`))
)
require.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(context.Background(),
client,
schema.NewRealm(schema.New("main").AddTables(users))),
))
require.Equal(t, `erDiagram
users {
int id
text name
}
`, b.String())
b.Reset()
users.SetPrimaryKey(
schema.NewPrimaryKey(users.Columns[0]),
)
posts := schema.NewTable("posts").
AddColumns(
schema.NewIntColumn("id", "int"),
schema.NewStringColumn("text", "text"),
)
posts.SetPrimaryKey(
schema.NewPrimaryKey(posts.Columns...),
)
posts.AddForeignKeys(
schema.NewForeignKey("owner_id").
AddColumns(posts.Columns[0]).
SetRefTable(users).
AddRefColumns(users.Columns[0]),
)
require.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(
context.Background(),
client, schema.NewRealm(schema.New("main").AddTables(users, posts)))),
)
require.Equal(t, `erDiagram
users {
int id PK
text name
}
posts {
int id PK,FK
text text PK
}
posts }o--o| users : owner_id
`, b.String())
b.Reset()
require.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(
context.Background(),
client,
schema.NewRealm(
schema.New("main").AddTables(users),
schema.New("temp").AddTables(posts),
),
)))
require.Equal(t, `erDiagram
main_users["main.users"] {
int id PK
text name
}
temp_posts["temp.posts"] {
int id PK,FK
text text PK
}
temp_posts }o--o| main_users : owner_id
`, b.String())
b.Reset()
users.
AddColumns(
schema.NewIntColumn("best_friend_id", "int"),
).
AddIndexes(
schema.NewUniqueIndex("best_friend_id").
AddColumns(users.Columns[2]),
).
AddForeignKeys(
schema.NewForeignKey("best_friend_id").
AddColumns(users.Columns[2]).
SetRefTable(users).
AddRefColumns(users.Columns[0]),
)
require.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(
context.Background(),
client,
schema.NewRealm(schema.New("main").AddTables(users)),
)))
require.Equal(t, `erDiagram
users {
int id PK
text name
int best_friend_id FK
}
users |o--o| users : best_friend_id
`, b.String())
b.Reset()
users.
AddColumns(
schema.NewFloatColumn("time duration", "double precision"),
)
require.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(
context.Background(),
client,
schema.NewRealm(schema.New("main").AddTables(users)),
)))
require.Equal(t, `erDiagram
users {
int id PK
text name
int best_friend_id FK
double_precision time_duration
}
users |o--o| users : best_friend_id
`, b.String())
}
func TestSchemaInspect_RedactedURL(t *testing.T) {
cmd := cmdlog.SchemaInspect{
URL: "mysql://root:password@localhost:3306/test",
}
u, err := cmd.RedactedURL()
require.NoError(t, err)
require.Equal(t, "mysql://root:xxxxx@localhost:3306/test", u)
}
func TestSchemaDiff_MarshalSQL(t *testing.T) {
client, err := sqlclient.Open(context.Background(), "sqlite://ci?mode=memory&_fk=1")
require.NoError(t, err)
defer client.Close()
diff := cmdlog.NewSchemaDiff(context.Background(), client, nil, nil, schema.Changes{
&schema.AddTable{
T: schema.NewTable("users").
AddColumns(
schema.NewIntColumn("id", "int"),
),
},
})
b, err := diff.MarshalSQL()
require.NoError(t, err)
require.Equal(t, "-- Create \"users\" table\nCREATE TABLE `users` (`id` int NOT NULL);\n", b)
}
func TestMigrateSet(t *testing.T) {
var (
b bytes.Buffer
log = &cmdlog.MigrateSet{}
)
color.NoColor = true
require.NoError(t, cmdlog.MigrateSetTemplate.Execute(&b, log))
require.Empty(t, b.String())
log.Current = &migrate.Revision{Version: "1"}
require.NoError(t, cmdlog.MigrateSetTemplate.Execute(&b, log))
require.Empty(t, b.String())
log.Current = &migrate.Revision{Version: "1"}
log.Removed(&migrate.Revision{Version: "2"})
log.Removed(&migrate.Revision{Version: "3", Description: "desc"})
require.NoError(t, cmdlog.MigrateSetTemplate.Execute(&b, log))
require.Equal(t, `Current version is 1 (2 removed):
- 2
- 3 (desc)
`, b.String())
b.Reset()
log.Set(&migrate.Revision{Version: "1.1", Description: "desc"})
require.NoError(t, cmdlog.MigrateSetTemplate.Execute(&b, log))
require.Equal(t, `Current version is 1 (1 set, 2 removed):
+ 1.1 (desc)
- 2
- 3 (desc)
`, b.String())
b.Reset()
log.Current, log.Revisions = nil, nil
log.Removed(&migrate.Revision{Version: "2"})
log.Removed(&migrate.Revision{Version: "3", Description: "desc"})
require.NoError(t, cmdlog.MigrateSetTemplate.Execute(&b, log))
require.Equal(t, `All revisions deleted (2 in total):
- 2
- 3 (desc)
`, b.String())
}
func TestMigrateApply(t *testing.T) {
var (
b bytes.Buffer
d migrate.MemDir
log = &cmdlog.MigrateApply{Start: time.Now()}
)
log.End = log.Start.Add(time.Millisecond * 10)
color.NoColor = true
require.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))
require.Equal(t, "No migration files to execute\n", b.String())
require.NoError(t, d.WriteFile("20240116000001.sql", nil))
require.NoError(t, d.WriteFile("20240116000002.sql", nil))
require.NoError(t, d.WriteFile("20240116000003.sql", nil))
files, err := d.Files()
require.NoError(t, err)
// Single file.
b.Reset()
log.Pending = files[:1]
log.Target = files[0].Version()
log.Applied = []*cmdlog.AppliedFile{
{
File: files[0],
Start: log.Start,
End: log.Start.Add(time.Millisecond * 5),
Applied: []string{
"CREATE TABLE users (id int NOT NULL);",
"CREATE TABLE posts (id int NOT NULL);",
},
},
}
require.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))
require.Equal(t, `Migrating to version 20240116000001 (1 migrations in total):
-- migrating version 20240116000001
-> CREATE TABLE users (id int NOT NULL);
-> CREATE TABLE posts (id int NOT NULL);
-- ok (5ms)
-------------------------
-- 10ms
-- 1 migration
-- 2 sql statements
`, b.String())
// Multiple files, with errors.
b.Reset()
log.Pending = files[1:3]
log.Current = files[0].Version()
log.Target = files[2].Version()
log.Applied = []*cmdlog.AppliedFile{
{
File: files[1],
Start: log.Start,
End: log.Start.Add(time.Millisecond),
Applied: []string{
"CREATE TABLE t1 (id int NOT NULL);",
"CREATE TABLE t2 (id int NOT NULL);",
},
},
{
File: files[2],
Start: log.Start,
End: log.Start.Add(time.Millisecond * 2),
Applied: []string{
"CREATE TABLE t3 (id int NOT NULL);",
"CREATE TABLE t4 (id int NOT NULL);",
},
Error: &cmdlog.StmtError{
Stmt: "CREATE TABLE t4 (id int NOT NULL);",
Text: "table t4 already exists",
},
},
}
require.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))
require.Equal(t, `Migrating to version 20240116000003 from 20240116000001 (2 migrations in total):
-- migrating version 20240116000002
-> CREATE TABLE t1 (id int NOT NULL);
-> CREATE TABLE t2 (id int NOT NULL);
-- ok (1ms)
-- migrating version 20240116000003
-> CREATE TABLE t3 (id int NOT NULL);
-> CREATE TABLE t4 (id int NOT NULL);
table t4 already exists
-------------------------
-- 10ms
-- 1 migration ok, 1 with errors
-- 3 sql statements ok, 1 with errors
`, b.String())
// Multiple files with checks, and without errors.
b.Reset()
log.Applied = []*cmdlog.AppliedFile{
{
File: files[1],
Start: log.Start,
End: log.Start.Add(time.Millisecond),
Applied: []string{
"CREATE TABLE t1 (id int NOT NULL);",
"CREATE TABLE t2 (id int NOT NULL);",
},
},
{
File: files[2],
Start: log.Start,
End: log.Start.Add(time.Millisecond * 2),
Checks: []*cmdlog.FileChecks{
{
Stmts: []*cmdlog.Check{
{Stmt: "SELECT 1;"},
{Stmt: "SELECT true;"},
},
Start: log.Start,
End: log.Start.Add(time.Millisecond * 2),
},
},
Applied: []string{
"CREATE TABLE t3 (id int NOT NULL);",
},
},
}
require.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))
require.Equal(t, `Migrating to version 20240116000003 from 20240116000001 (2 migrations in total):
-- migrating version 20240116000002
-> CREATE TABLE t1 (id int NOT NULL);
-> CREATE TABLE t2 (id int NOT NULL);
-- ok (1ms)
-- checks before migrating version 20240116000003
-> SELECT 1;
-> SELECT true;
-- ok (2ms)
-- migrating version 20240116000003
-> CREATE TABLE t3 (id int NOT NULL);
-- ok (2ms)
-------------------------
-- 10ms
-- 2 migrations
-- 2 checks
-- 3 sql statements
`, b.String())
// Multiple files with check errors.
b.Reset()
log.Applied = []*cmdlog.AppliedFile{
{
File: files[1],
Start: log.Start,
End: log.Start.Add(time.Millisecond),
Applied: []string{
"CREATE TABLE t1 (id int NOT NULL);",
"CREATE TABLE t2 (id int NOT NULL);",
},
},
{
File: files[2],
Start: log.Start,
End: log.Start.Add(time.Millisecond * 2),
Checks: []*cmdlog.FileChecks{
{
Stmts: []*cmdlog.Check{
{Stmt: "SELECT 1;"},
{Stmt: "SELECT false;", Error: new(string)},
},
Start: log.Start,
End: log.Start.Add(time.Millisecond * 2),
Error: &cmdlog.StmtError{Text: "assertion failure"},
},
},
Error: &cmdlog.StmtError{
Text: "assertion failure",
},
},
}
require.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))
require.Equal(t, `Migrating to version 20240116000003 from 20240116000001 (2 migrations in total):
-- migrating version 20240116000002
-> CREATE TABLE t1 (id int NOT NULL);
-> CREATE TABLE t2 (id int NOT NULL);
-- ok (1ms)
-- checks before migrating version 20240116000003
-> SELECT 1;
-> SELECT false;
assertion failure
-------------------------
-- 10ms
-- 1 migration ok, 1 with errors
-- 1 check ok, 1 failure
-- 2 sql statements
`, b.String())
// Multiple files with multiple checks.
b.Reset()
log.Applied = []*cmdlog.AppliedFile{
{
File: files[1],
Start: log.Start,
End: log.Start.Add(time.Millisecond),
Applied: []string{
"CREATE TABLE t1 (id int NOT NULL);",
"CREATE TABLE t2 (id int NOT NULL);",
},
},
{
File: files[2],
Start: log.Start,
End: log.Start.Add(time.Millisecond * 2),
Checks: []*cmdlog.FileChecks{
{
Name: "checks/1",
Stmts: []*cmdlog.Check{
{Stmt: "SELECT 1;"},
{Stmt: "SELECT true;"},
},
Start: log.Start,
End: log.Start.Add(time.Millisecond * 2),
},
{
Name: "checks/2",
Stmts: []*cmdlog.Check{
{Stmt: "SELECT 1;"},
{Stmt: "SELECT false;", Error: new(string)},
},
Start: log.Start,
End: log.Start.Add(time.Millisecond * 2),
Error: &cmdlog.StmtError{Text: "assertion failure"},
},
},
Error: &cmdlog.StmtError{
Text: "assertion failure",
},
},
}
require.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))
require.Equal(t, `Migrating to version 20240116000003 from 20240116000001 (2 migrations in total):
-- migrating version 20240116000002
-> CREATE TABLE t1 (id int NOT NULL);
-> CREATE TABLE t2 (id int NOT NULL);
-- ok (1ms)
-- checks before migrating version 20240116000003
-> SELECT 1;
-> SELECT true;
-- ok (2ms)
-- checks before migrating version 20240116000003
-> SELECT 1;
-> SELECT false;
assertion failure
-------------------------
-- 10ms
-- 1 migration ok, 1 with errors
-- 3 checks ok, 1 failure
-- 2 sql statements
`, b.String())
// Error during plan stage.
b.Reset()
log.Applied = nil
log.Error = `sql/migrate: scanning statements from "20240116000003.sql": 5:115: unclosed quote '\''`
require.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))
require.Equal(t, `Migrating to version 20240116000003 from 20240116000001 (2 migrations in total):
sql/migrate: scanning statements from "20240116000003.sql": 5:115: unclosed quote '\''
-------------------------
-- 10ms
`, b.String())
}
func TestReporter_Status(t *testing.T) {
var (
buf strings.Builder
ctx = context.Background()
)
// Clean.
dir, err := migrate.NewLocalDir(filepath.Join("../migrate/testdata", "broken"))
require.NoError(t, err)
c, err := sqlclient.Open(ctx, "sqlite://?mode=memory")
require.NoError(t, err)
defer c.Close()
rr := &cmdlog.StatusReporter{Client: c, Dir: dir}
report, err := rr.Report(ctx)
require.NoError(t, err)
require.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))
require.Equal(t, `Migration Status: PENDING
-- Current Version: No migration applied yet
-- Next Version: 1
-- Executed Files: 0
-- Pending Files: 3
`, buf.String())
// Applied one.
buf.Reset()
rrw, err := cmdmigrate.NewEntRevisions(ctx, c)
require.NoError(t, err)
require.NoError(t, rrw.Migrate(ctx))
ex, err := migrate.NewExecutor(c.Driver, dir, rrw)
require.NoError(t, err)
require.NoError(t, ex.ExecuteN(ctx, 1))
rr = &cmdlog.StatusReporter{Client: c, Dir: dir}
report, err = rr.Report(ctx)
require.NoError(t, err)
require.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))
require.Equal(t, `Migration Status: PENDING
-- Current Version: 1
-- Next Version: 2
-- Executed Files: 1
-- Pending Files: 2
`, buf.String())
// Applied two.
buf.Reset()
require.NoError(t, err)
require.NoError(t, ex.ExecuteN(ctx, 1))
rr = &cmdlog.StatusReporter{Client: c, Dir: dir}
report, err = rr.Report(ctx)
require.NoError(t, err)
require.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))
require.Equal(t, `Migration Status: PENDING
-- Current Version: 2
-- Next Version: 3
-- Executed Files: 2
-- Pending Files: 1
`, buf.String())
// Partial three.
buf.Reset()
require.NoError(t, err)
require.Error(t, ex.ExecuteN(ctx, 1))
rr = &cmdlog.StatusReporter{Client: c, Dir: dir}
report, err = rr.Report(ctx)
require.NoError(t, err)
require.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))
require.Equal(t, `Migration Status: PENDING
-- Current Version: 3 (1 statements applied)
-- Next Version: 3 (1 statements left)
-- Executed Files: 3 (last one partially)
-- Pending Files: 1
Last migration attempt had errors:
-- SQL: THIS LINE ADDS A SYNTAX ERROR;
-- ERROR: near "THIS": syntax error
`, buf.String())
// Fixed three - okay.
buf.Reset()
dir2, err := migrate.NewLocalDir(filepath.Join("../migrate/testdata", "fixed"))
require.NoError(t, err)
*dir = *dir2
require.NoError(t, err)
require.NoError(t, ex.ExecuteN(ctx, 1))
rr = &cmdlog.StatusReporter{Client: c, Dir: dir}
report, err = rr.Report(ctx)
require.NoError(t, err)
require.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))
require.Equal(t, `Migration Status: OK
-- Current Version: 3
-- Next Version: Already at latest version
-- Executed Files: 3
-- Pending Files: 0
`, buf.String())
}
func TestReporter_OutOfOrder(t *testing.T) {
var (
buf strings.Builder
ctx = context.Background()
)
dir, err := migrate.NewLocalDir(t.TempDir())
require.NoError(t, err)
require.NoError(t, dir.WriteFile("1.sql", []byte("create table t1(c int);")))
require.NoError(t, dir.WriteFile("2.sql", []byte("create table t2(c int);")))
sum, err := dir.Checksum()
require.NoError(t, err)
require.NoError(t, migrate.WriteSumFile(dir, sum))
c, err := sqlclient.Open(ctx, "sqlite://?mode=memory")
require.NoError(t, err)
defer c.Close()
rr := &cmdlog.StatusReporter{Client: c, Dir: dir}
rrw, err := cmdmigrate.NewEntRevisions(ctx, c)
require.NoError(t, err)
require.NoError(t, rrw.Migrate(ctx))
report, err := rr.Report(ctx)
require.NoError(t, err)
require.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))
require.Equal(t, `Migration Status: PENDING
-- Current Version: No migration applied yet
-- Next Version: 1
-- Executed Files: 0
-- Pending Files: 2
`, buf.String())
ex, err := migrate.NewExecutor(c.Driver, dir, rrw)
require.NoError(t, err)
require.NoError(t, ex.ExecuteN(ctx, 2))
// One file was added out of order.
buf.Reset()
require.NoError(t, dir.WriteFile("1.5.sql", []byte("create table t1_5(c int);")))
sum, err = dir.Checksum()
require.NoError(t, err)
require.NoError(t, migrate.WriteSumFile(dir, sum))
report, err = rr.Report(ctx)
require.NoError(t, err)
require.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))
require.Equal(t, `Migration Status: PENDING
-- Current Version: 2
-- Next Version: UNKNOWN
-- Executed Files: 2
-- Pending Files: 1 (out of order)
ERROR: migration file 1.5.sql was added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error
`, buf.String())
// Multiple files were added our of order.
buf.Reset()
require.NoError(t, dir.WriteFile("1.6.sql", []byte("create table t1_6(c int);")))
sum, err = dir.Checksum()
require.NoError(t, err)
require.NoError(t, migrate.WriteSumFile(dir, sum))
report, err = rr.Report(ctx)
require.NoError(t, err)
require.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))
require.Equal(t, `Migration Status: PENDING
-- Current Version: 2
-- Next Version: UNKNOWN
-- Executed Files: 2
-- Pending Files: 2 (out of order)
ERROR: migration files 1.5.sql, 1.6.sql were added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error
`, buf.String())
// A mix of pending and out of order files.
buf.Reset()
require.NoError(t, dir.WriteFile("3.sql", []byte("create table t3(c int);")))
sum, err = dir.Checksum()
require.NoError(t, err)
require.NoError(t, migrate.WriteSumFile(dir, sum))
report, err = rr.Report(ctx)
require.NoError(t, err)
require.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))
require.Equal(t, `Migration Status: PENDING
-- Current Version: 2
-- Next Version: UNKNOWN
-- Executed Files: 2
-- Pending Files: 3 (2 out of order)
ERROR: migration files 1.5.sql, 1.6.sql were added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error
`, buf.String())
}
func TestWarnOnce(t *testing.T) {
b := &strings.Builder{}
require.NoError(t, cmdlog.WarnOnce(b, "one"))
require.NoError(t, cmdlog.WarnOnce(b, "two"))
require.Equal(t, "one", b.String())
var wg sync.WaitGroup
b = &strings.Builder{}
wg.Add(5)
for i := 0; i < 5; i++ {
go func() {
defer wg.Done()
require.NoError(t, cmdlog.WarnOnce(b, "one"))
}()
}
wg.Wait()
require.Equal(t, "one", b.String())
// Ensure the type is not assignable.
require.Panics(t, func() {
var m sync.Map
m.LoadOrStore(unassignable{}, "text")
})
b.Reset()
require.NoError(t, cmdlog.WarnOnce(unassignable{Writer: b}, "done"))
require.Equal(t, "done", b.String())
}
type unassignable struct {
_ func()
io.Writer
}
func (a unassignable) Write(p []byte) (n int, err error) { return a.Writer.Write(p) }
================================================
FILE: cmd/atlas/internal/cmdstate/cmdstate.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdstate
import (
"encoding/json"
"os"
"path/filepath"
"reflect"
"sync"
"testing"
"github.com/mitchellh/go-homedir"
)
// DefaultDir is the directory where CLI state is stored.
const DefaultDir = "~/.atlas"
// File is a state file for the given type.
type File[T any] struct {
// Dir where the file is stored. If empty, DefaultDir is used.
Dir string
// Name of the file. Suffixed with .json.
Name string
}
// Read reads the value from the file system.
func (f File[T]) Read() (v T, err error) {
path, err := f.Path()
if err != nil {
return v, err
}
switch buf, err := os.ReadFile(path); {
case os.IsNotExist(err):
return newT(v), nil
case err != nil:
return v, err
default:
err = json.Unmarshal(buf, &v)
return v, err
}
}
// Write writes the value to the file system.
func (f File[T]) Write(t T) error {
buf, err := json.Marshal(t)
if err != nil {
return err
}
path, err := f.Path()
if err != nil {
return err
}
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
return err
}
return os.WriteFile(path, buf, 0666)
}
// Path returns the path to the file.
func (f File[T]) Path() (string, error) {
name := f.Name
if filepath.Ext(name) == "" {
name += ".json"
}
if f.Dir != "" {
return filepath.Join(f.Dir, name), nil
}
path, err := homedir.Expand(filepath.Join(DefaultDir, name))
if err != nil {
return "", err
}
return path, nil
}
// newT ensures the type is initialized.
func newT[T any](t T) T {
if rt := reflect.TypeOf(t); rt.Kind() == reflect.Ptr {
return reflect.New(rt.Elem()).Interface().(T)
}
return t
}
// muDisableCache ensures homedir.DisableCache is not changed concurrently on tests.
var muDisableCache sync.Mutex
// TestingHome is a helper function for testing that
// sets the HOME directory to a temporary directory.
func TestingHome(t *testing.T) string {
muDisableCache.Lock()
homedir.DisableCache = true
t.Cleanup(func() {
homedir.DisableCache = false
muDisableCache.Unlock()
})
home := t.TempDir()
t.Setenv("HOME", home)
return home
}
================================================
FILE: cmd/atlas/internal/cmdstate/cmdstate_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdstate_test
import (
"os"
"path/filepath"
"testing"
"ariga.io/atlas/cmd/atlas/internal/cmdstate"
"github.com/mitchellh/go-homedir"
"github.com/stretchr/testify/require"
)
func TestFile(t *testing.T) {
homedir.DisableCache = true
t.Cleanup(func() { homedir.DisableCache = false })
type T struct{ V string }
f := cmdstate.File[T]{Name: "test", Dir: t.TempDir()}
v, err := f.Read()
require.NoError(t, err)
require.Equal(t, T{}, v)
require.NoError(t, f.Write(T{V: "v"}))
v, err = f.Read()
require.NoError(t, err)
require.Equal(t, T{V: "v"}, v)
home := t.TempDir()
t.Setenv("HOME", home)
f = cmdstate.File[T]{Name: "t"}
_, err = f.Read()
require.NoError(t, err)
dirs, err := os.ReadDir(home)
require.NoError(t, err)
require.Empty(t, dirs)
require.NoError(t, f.Write(T{V: "v"}))
dirs, err = os.ReadDir(home)
require.NoError(t, err)
require.Len(t, dirs, 1)
require.Equal(t, ".atlas", dirs[0].Name())
dirs, err = os.ReadDir(filepath.Join(home, ".atlas"))
require.NoError(t, err)
require.Len(t, dirs, 1)
require.Equal(t, "t.json", dirs[0].Name())
v, err = f.Read()
require.NoError(t, err)
require.Equal(t, T{V: "v"}, v)
}
================================================
FILE: cmd/atlas/internal/docker/docker.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package docker
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"log"
"net"
"net/url"
"os"
"os/exec"
"path"
"strconv"
"strings"
"time"
"ariga.io/atlas/sql/sqlclient"
"github.com/go-sql-driver/mysql"
)
const (
pass = "pass"
passSQLServer = "P@ssw0rd0995"
)
type (
// Config is used to configure container creation.
Config struct {
driver string // driver to open connections with.
setup []string // contains statements to execute once the service is up
// User is the user to connect to the database.
User *url.Userinfo
// Internal Port to expose and connect to.
Port string
// Image is the name of the image to pull and run.
Image string
// Env vars to pass to the docker container.
Env []string
// Database name to create and connect on init.
Database string
// Out is a custom writer to send docker cli output to.
Out io.Writer
// ConnOptions allows configuring the underlying connection pool.
ConnOptions *ConnOptions
}
// A Container is an instance of a created container.
Container struct {
Config // Config used to create this container
// ID of the container.
ID string
// Port on the host this containers service is bound to.
Port string
}
// ConnOptions allows configuring the underlying connection pool.
ConnOptions struct {
MaxOpen int
MaxIdle int
MaxLifetime time.Duration
MaxIdleTime time.Duration
}
// ConfigOption allows configuring Config with functional arguments.
ConfigOption func(*Config) error
)
// NewConfig returns a new config with the given options applied.
func NewConfig(opts ...ConfigOption) (*Config, error) {
c := &Config{Out: io.Discard}
for _, opt := range opts {
if err := opt(c); err != nil {
return nil, err
}
}
return c, nil
}
// Well-known DB drivers
const (
DriverMySQL = "mysql"
DriverMariaDB = "mariadb"
DriverPostgres = "postgres"
DriverSQLServer = "sqlserver"
DriverClickHouse = "clickhouse"
)
const (
PostgresPostGIS = "postgis"
PostgresPGVector = "pgvector"
)
// FromURL parses a URL in the format of
// "docker://driver/tag[/dbname]" and returns a Config.
func FromURL(u *url.URL, opts ...ConfigOption) (*Config, error) {
var (
parts = strings.Split(strings.TrimPrefix(u.Path, "/"), "/")
idxTag = len(parts) - 1
dbName string
)
// Check if the last part is a tag or a database name.
if idxTag > 0 && !strings.ContainsRune(parts[idxTag], ':') {
// The last part is not a tag, so it must be a database name.
dbName, idxTag = parts[idxTag], idxTag-1
}
var baseOpts []ConfigOption
var tag string
// Support docker+driver://[:]
driver, customImage := strings.CutPrefix(u.Scheme, "docker+")
if customImage {
// The image is fully specified in the URL.
img := path.Join(parts[:idxTag+1]...)
if u.Host != "" && u.Host != "_" {
img = path.Join(u.Host, img)
}
baseOpts = append(baseOpts, Image(img))
} else {
driver = u.Host
if idxTag >= 0 {
tag = parts[idxTag]
}
}
var (
err error
cfg *Config
)
switch driver {
case DriverMySQL:
if dbName != "" {
baseOpts = append(baseOpts,
Database(dbName),
Env("MYSQL_DATABASE="+dbName),
Setup(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s`", dbName)),
)
}
cfg, err = MySQL(tag, append(baseOpts, opts...)...)
case "maria":
driver = DriverMariaDB
fallthrough
case DriverMariaDB:
if dbName != "" {
baseOpts = append(baseOpts,
Database(dbName),
Env("MYSQL_DATABASE="+dbName),
Setup(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s`", dbName)),
)
}
cfg, err = MariaDB(tag, append(baseOpts, opts...)...)
case PostgresPostGIS:
baseOpts = append(baseOpts, Image(
fmt.Sprintf("%[1]s/%[1]s:%[2]s", PostgresPostGIS, tag),
))
if dbName != "" && dbName != "postgres" {
// Create manually the PostgreSQL database instead of using the POSTGRES_DB because
// PostGIS automatically creates and install the following extensions and schemas:
// Schemas: tiger, tiger_data, topology.
// Extensions: postgis, postgis_topology, postgis_tiger_geocoder.
baseOpts = append(
baseOpts, Database(dbName), Setup(fmt.Sprintf("CREATE DATABASE %q", dbName)),
)
}
driver = DriverPostgres
cfg, err = PostgreSQL(tag, append(baseOpts, opts...)...)
case PostgresPGVector:
baseOpts = append(baseOpts, Image(
fmt.Sprintf("%[1]s/%[1]s:%[2]s", PostgresPGVector, tag),
))
if dbName != "" {
baseOpts = append(baseOpts, Database(dbName), Env("POSTGRES_DB="+dbName))
}
driver = DriverPostgres
cfg, err = PostgreSQL(tag, append(baseOpts, opts...)...)
case DriverPostgres:
if dbName != "" {
baseOpts = append(baseOpts, Database(dbName), Env("POSTGRES_DB="+dbName))
}
cfg, err = PostgreSQL(tag, append(baseOpts, opts...)...)
case DriverSQLServer:
if dbName != "" && dbName != "master" {
baseOpts = append(baseOpts,
Database(dbName),
Setup(fmt.Sprintf("CREATE DATABASE [%s]", dbName)),
)
}
cfg, err = SQLServer(tag, append(baseOpts, opts...)...)
case DriverClickHouse:
if dbName != "" {
baseOpts = append(baseOpts,
Database(dbName),
Env("CLICKHOUSE_DB="+dbName),
Setup(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s`", dbName)),
)
}
cfg, err = ClickHouse(tag, append(baseOpts, opts...)...)
default:
return nil, fmt.Errorf("unsupported docker image %q", driver)
}
if err != nil {
return nil, err
}
cfg.driver = driver
return cfg, nil
}
// ImageURL returns the base URL for the given driver and image.
func ImageURL(driver string, image string) (*url.URL, error) {
switch {
case driver == "" && image == "":
return nil, errors.New("driver and image cannot be empty")
case driver == "":
return nil, errors.New("driver cannot be empty")
case image == "":
return nil, errors.New("image cannot be empty")
default:
u := &url.URL{Scheme: "docker+" + driver, Host: "_", Path: image}
if idx := strings.IndexByte(image, '/'); idx != -1 {
u.Host, u.Path = image[:idx], image[idx+1:]
}
return u, nil
}
}
// Atlas DockerHub user contains the MySQL
// and MariaDB images with faster boot times.
const hubUser = "arigaio"
// MySQL returns a new Config for a MySQL image.
func MySQL(version string, opts ...ConfigOption) (*Config, error) {
return NewConfig(
append(
[]ConfigOption{
Image(hubUser, "mysql:"+version),
Userinfo(url.UserPassword("root", pass)),
Port("3306"),
Env("MYSQL_ROOT_PASSWORD=" + pass),
},
opts...,
)...,
)
}
// MariaDB returns a new Config for a MariaDB image.
func MariaDB(version string, opts ...ConfigOption) (*Config, error) {
return MySQL(version, append([]ConfigOption{Image(hubUser, "mariadb:"+version)}, opts...)...)
}
// PostgreSQL returns a new Config for a PostgreSQL image.
func PostgreSQL(version string, opts ...ConfigOption) (*Config, error) {
return NewConfig(
append(
[]ConfigOption{
Image("postgres:" + version),
Userinfo(url.UserPassword("postgres", pass)),
Port("5432"),
Database("postgres"),
Env("POSTGRES_PASSWORD=" + pass),
},
opts...,
)...,
)
}
// SQLServer returns a new Config for a SQLServer image.
func SQLServer(version string, opts ...ConfigOption) (*Config, error) {
return NewConfig(
append(
[]ConfigOption{
Image("mcr.microsoft.com/mssql/server:" + version),
Userinfo(url.UserPassword("sa", passSQLServer)),
Port("1433"),
Database("master"),
Env(
"ACCEPT_EULA=Y",
"MSSQL_PID=Developer",
"MSSQL_SA_PASSWORD="+passSQLServer,
),
},
opts...,
)...,
)
}
// ClickHouse returns a new Config for a ClickHouse image.
func ClickHouse(version string, opts ...ConfigOption) (*Config, error) {
return NewConfig(
append(
[]ConfigOption{
Image("clickhouse/clickhouse-server:" + version),
Userinfo(url.UserPassword("default", pass)),
Port("9000"),
Env("CLICKHOUSE_PASSWORD=" + pass),
},
opts...,
)...,
)
}
// Image sets the docker image to use. For example:
//
// Image("mysql")
// Image("arigaio", "mysql")
// Image("postgres:13")
func Image(parts ...string) ConfigOption {
return func(c *Config) error {
if len(parts) == 0 || len(parts) > 2 {
return errors.New("image path must be in the format of 'image' or 'user/image'")
}
c.Image = strings.TrimSuffix(path.Join(parts...), ":")
return nil
}
}
// Port sets the port the container services exposes. For example:
//
// Port("3306")
// Port("5432")
func Port(p string) ConfigOption {
return func(c *Config) error {
c.Port = p
return nil
}
}
// Env sets the environment variables to pass to the container. For example:
//
// Config(Image("mysql"), Env("MYSQL_ROOT_PASSWORD=password"))
// Config(Image("postgres"), Env("MYSQL_ROOT_PASSWORD=password"))
func Env(env ...string) ConfigOption {
return func(c *Config) error {
c.Env = append(c.Env, env...)
return nil
}
}
// Database sets the database name to connect to. For example:
//
// Database("test")
func Database(name string) ConfigOption {
return func(c *Config) error {
c.Database = name
return nil
}
}
// Userinfo sets the user to connect to the database. For example:
//
// Userinfo(url.User("root", "pass"))
func Userinfo(u *url.Userinfo) ConfigOption {
return func(c *Config) error {
c.User = u
return nil
}
}
// Out sets an io.Writer to use when running docker commands. For example:
//
// buf := new(bytes.Buffer)
// NewConfig(Out(buf))
func Out(w io.Writer) ConfigOption {
return func(c *Config) error {
c.Out = w
return nil
}
}
// Setup adds statements to execute once the service is ready. For example:
//
// setup("CREATE DATABASE IF NOT EXISTS test")
// setup("DROP SCHEMA IF EXISTS public CASCADE")
func Setup(s ...string) ConfigOption {
return func(c *Config) error {
c.setup = append(c.setup, s...)
return nil
}
}
// Conn sets the config connection configuration.
func Conn(s *ConnOptions) ConfigOption {
return func(c *Config) error {
c.ConnOptions = s
return nil
}
}
// Run pulls and starts a new docker container from the Config.
func (c *Config) Run(ctx context.Context) (*Container, error) {
// Make sure the configuration is not missing critical values.
if err := c.validate(); err != nil {
return nil, err
}
// Get a free host TCP port the container can bind its exposed service port on.
p, err := freePort()
if err != nil {
return nil, fmt.Errorf("getting open port: %w", err)
}
// Run the container.
args := []string{"docker", "run", "--rm", "--detach"}
for _, e := range c.Env {
args = append(args, "-e", e)
}
args = append(args, "-p", fmt.Sprintf("%s:%s", p, c.Port), c.Image)
cmd := exec.CommandContext(ctx, args[0], args[1:]...) //nolint:gosec
stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
cmd.Stdout, cmd.Stderr = io.MultiWriter(c.Out, stdout), stderr
if err := cmd.Run(); err != nil {
if stderr.Len() > 0 {
err = errors.New(strings.TrimSpace(stderr.String()))
}
return nil, err
}
return &Container{
Config: *c,
ID: strings.TrimSpace(stdout.String()),
Port: p,
}, nil
}
// Close stops and removes this container.
func (c *Container) Close() error {
return exec.Command("docker", "kill", c.ID).Run() //nolint:gosec
}
// Wait waits for this container to be ready.
func (c *Container) Wait(ctx context.Context, timeout time.Duration) error {
fmt.Fprintln(c.Out, "Waiting for service to be ready ... ")
mysql.SetLogger(log.New(io.Discard, "", 1))
defer mysql.SetLogger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile))
if timeout > time.Minute {
timeout = time.Minute
}
var (
done = time.After(timeout)
u, err = c.URL()
)
if err != nil {
return err
}
pingURL := c.PingURL(*u)
for {
select {
case <-time.After(100 * time.Millisecond):
var client *sqlclient.Client
// Ping against the root connection.
client, err = sqlclient.Open(ctx, pingURL)
if err != nil {
continue
}
db := client.DB
if err = db.PingContext(ctx); err != nil {
continue
}
for _, s := range c.setup {
if _, err := db.ExecContext(ctx, s); err != nil {
err = errors.Join(err, db.Close())
return fmt.Errorf("%q: %w", s, err)
}
}
_ = db.Close()
fmt.Fprintln(c.Out, "Service is ready to connect!")
return nil
case <-ctx.Done():
return ctx.Err()
case <-done:
if err != nil {
return fmt.Errorf("timeout: %w", err)
}
return errors.New("timeout")
}
}
}
// URL returns a URL to connect to the Container.
func (c *Container) URL() (*url.URL, error) {
host := "localhost"
// Check if the DOCKER_HOST env var is set.
// If it is, use the host from the URL.
if h := os.Getenv("DOCKER_HOST"); h != "" {
u, err := url.Parse(h)
if err != nil {
return nil, err
}
// Only use the hostname if the scheme is tcp or ssh.
// For unix sockets, the hostname is localhost.
// See https://docs.docker.com/reference/cli/docker/#host
if u.Scheme == "tcp" || u.Scheme == "ssh" {
host = u.Hostname()
}
}
u := &url.URL{
Scheme: c.driver,
User: c.User,
Host: fmt.Sprintf("%s:%s", host, c.Port),
}
switch c.driver {
case DriverSQLServer:
q := u.Query()
q.Set("database", c.Database)
u.RawQuery = q.Encode()
case DriverPostgres:
q := u.Query()
q.Set("sslmode", "disable")
u.Path, u.RawQuery = c.Database, q.Encode()
if u.Path == "" {
u.Path = "/"
}
case DriverMySQL, DriverMariaDB, DriverClickHouse: // MySQL compatible
u.Path = c.Database
default:
return nil, fmt.Errorf("unknown driver: %q", c.driver)
}
return u, nil
}
// PingURL returns a URL to ping the Container.
func (c *Container) PingURL(u url.URL) string {
switch c.driver {
case DriverSQLServer:
q := u.Query()
q.Del("database")
u.RawQuery = q.Encode()
return u.String()
default:
u.Path = "/"
return u.String()
}
}
// validate that no empty values are given.
func (c *Config) validate() error {
if c == nil || c.Image == "" || c.Port == "" || c.Out == nil {
return fmt.Errorf("invalid configuration %#v", c)
}
return nil
}
func freePort() (string, error) {
a, err := net.ResolveTCPAddr("tcp", ":0")
if err != nil {
return "", err
}
l, err := net.ListenTCP("tcp", a)
if err != nil {
return "", err
}
if err := l.Close(); err != nil {
return "", err
}
return strconv.Itoa(l.Addr().(*net.TCPAddr).Port), nil
}
func init() {
sqlclient.Register(
"docker",
sqlclient.OpenerFunc(Open),
sqlclient.RegisterFlavours(
"docker+postgres",
"docker+mysql", "docker+maria", "docker+mariadb", "docker+clickhouse",
"docker+sqlserver",
),
)
}
// Open a new docker client.
func Open(ctx context.Context, u *url.URL) (client *sqlclient.Client, err error) {
return OpenWithOpts(ctx, u)
}
// OpenWithOpts open a new docker client
func OpenWithOpts(ctx context.Context, u *url.URL, opts ...ConfigOption) (client *sqlclient.Client, err error) {
cfg, err := FromURL(u, opts...)
if err != nil {
return nil, err
}
qr := u.Query()
if qr.Has("v") || qr.Has("verbose") {
if err := Out(os.Stdout)(cfg); err != nil {
return nil, err
}
qr.Del("v")
qr.Del("verbose")
}
c, err := cfg.Run(ctx)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
if cerr := c.Close(); err != nil {
err = fmt.Errorf("%w: %v", err, cerr)
}
}
}()
if err = c.Wait(ctx, time.Minute); err != nil {
return nil, err
}
u1, err := c.URL()
if err != nil {
return nil, err
}
for k, v := range u1.Query() {
qr[k] = v
}
u1.RawQuery = qr.Encode()
if client, err = sqlclient.Open(ctx, u1.String()); err != nil {
return nil, err
}
client.Ephemeral = true
if s := c.ConnOptions; s != nil {
if s.MaxOpen > 0 {
client.DB.SetMaxOpenConns(s.MaxOpen)
}
if s.MaxIdle > 0 {
client.DB.SetMaxIdleConns(s.MaxIdle)
}
if s.MaxLifetime > 0 {
client.DB.SetConnMaxLifetime(s.MaxLifetime)
}
if s.MaxIdleTime > 0 {
client.DB.SetConnMaxIdleTime(s.MaxIdleTime)
}
}
client.AddClosers(c)
return client, nil
}
================================================
FILE: cmd/atlas/internal/docker/docker_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package docker
import (
"context"
"io"
"net/url"
"testing"
"github.com/stretchr/testify/require"
)
func TestDockerConfig(t *testing.T) {
ctx := context.Background()
// invalid config
_, err := (&Config{}).Run(ctx)
require.Error(t, err)
// MySQL
cfg, err := MySQL("latest", Out(io.Discard))
require.NoError(t, err)
require.Equal(t, &Config{
Image: "arigaio/mysql:latest",
User: url.UserPassword("root", pass),
Env: []string{"MYSQL_ROOT_PASSWORD=pass"},
Port: "3306",
Out: io.Discard,
}, cfg)
// MariaDB
cfg, err = MariaDB("latest", Out(io.Discard))
require.NoError(t, err)
require.Equal(t, &Config{
Image: "arigaio/mariadb:latest",
User: url.UserPassword("root", pass),
Env: []string{"MYSQL_ROOT_PASSWORD=pass"},
Port: "3306",
Out: io.Discard,
}, cfg)
// PostgreSQL
cfg, err = PostgreSQL("latest", Out(io.Discard))
require.NoError(t, err)
require.Equal(t, &Config{
Image: "postgres:latest",
User: url.UserPassword("postgres", pass),
Env: []string{"POSTGRES_PASSWORD=pass"},
Database: "postgres",
Port: "5432",
Out: io.Discard,
}, cfg)
// SQL Server
cfg, err = SQLServer("2022-latest", Out(io.Discard))
require.NoError(t, err)
require.Equal(t, &Config{
Image: "mcr.microsoft.com/mssql/server:2022-latest",
User: url.UserPassword("sa", passSQLServer),
Port: "1433",
Database: "master",
Out: io.Discard,
Env: []string{
"ACCEPT_EULA=Y",
"MSSQL_PID=Developer",
"MSSQL_SA_PASSWORD=" + passSQLServer,
},
}, cfg)
// ClickHouse
cfg, err = ClickHouse("23.11", Out(io.Discard))
require.NoError(t, err)
require.Equal(t, &Config{
Image: "clickhouse/clickhouse-server:23.11",
User: url.UserPassword("default", pass),
Port: "9000",
Out: io.Discard,
Env: []string{
"CLICKHOUSE_PASSWORD=pass",
},
}, cfg)
}
func TestFromURL(t *testing.T) {
u, err := url.Parse("docker://mysql")
require.NoError(t, err)
cfg, err := FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "mysql",
Image: "arigaio/mysql",
User: url.UserPassword("root", pass),
Env: []string{"MYSQL_ROOT_PASSWORD=pass"},
Port: "3306",
Out: io.Discard,
}, cfg)
u, err = url.Parse("docker://mysql/8")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "mysql",
Image: "arigaio/mysql:8",
User: url.UserPassword("root", pass),
Env: []string{"MYSQL_ROOT_PASSWORD=pass"},
Port: "3306",
Out: io.Discard,
}, cfg)
u, err = url.Parse("docker://mysql/latest/test")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "mysql",
Image: "arigaio/mysql:latest",
Database: "test",
Env: []string{"MYSQL_ROOT_PASSWORD=pass", "MYSQL_DATABASE=test"},
User: url.UserPassword("root", pass),
Port: "3306",
Out: io.Discard,
setup: []string{"CREATE DATABASE IF NOT EXISTS `test`"},
}, cfg)
u, err = url.Parse("docker://postgres/13")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "postgres",
Image: "postgres:13",
Database: "postgres",
Env: []string{"POSTGRES_PASSWORD=pass"},
User: url.UserPassword("postgres", pass),
Port: "5432",
Out: io.Discard,
}, cfg)
// PostGIS.
u, err = url.Parse("docker://postgis/14-3.4")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "postgres",
Image: "postgis/postgis:14-3.4",
Database: "postgres",
Env: []string{"POSTGRES_PASSWORD=pass"},
User: url.UserPassword("postgres", pass),
Port: "5432",
Out: io.Discard,
}, cfg)
u, err = url.Parse("docker://postgis/14-3.4/dev")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "postgres",
Image: "postgis/postgis:14-3.4",
Database: "dev",
Env: []string{"POSTGRES_PASSWORD=pass"},
User: url.UserPassword("postgres", pass),
Port: "5432",
Out: io.Discard,
setup: []string{`CREATE DATABASE "dev"`},
}, cfg)
// PGVector.
u, err = url.Parse("docker://pgvector/pg17")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "postgres",
Image: "pgvector/pgvector:pg17",
Database: "postgres",
Env: []string{"POSTGRES_PASSWORD=pass"},
User: url.UserPassword("postgres", pass),
Port: "5432",
Out: io.Discard,
}, cfg)
u, err = url.Parse("docker://pgvector/pg17/dev")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "postgres",
Image: "pgvector/pgvector:pg17",
Database: "dev",
Env: []string{"POSTGRES_PASSWORD=pass", "POSTGRES_DB=dev"},
User: url.UserPassword("postgres", pass),
Port: "5432",
Out: io.Discard,
}, cfg)
// SQL Server
u, err = url.Parse("docker://sqlserver")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "sqlserver",
Image: "mcr.microsoft.com/mssql/server",
Database: "master",
User: url.UserPassword("sa", passSQLServer),
Port: "1433",
Out: io.Discard,
Env: []string{
"ACCEPT_EULA=Y",
"MSSQL_PID=Developer",
"MSSQL_SA_PASSWORD=" + passSQLServer,
},
}, cfg)
u, err = url.Parse("docker://sqlserver/2022-latest")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "sqlserver",
Image: "mcr.microsoft.com/mssql/server:2022-latest",
Database: "master",
User: url.UserPassword("sa", passSQLServer),
Port: "1433",
Out: io.Discard,
Env: []string{
"ACCEPT_EULA=Y",
"MSSQL_PID=Developer",
"MSSQL_SA_PASSWORD=" + passSQLServer,
},
}, cfg)
u, err = url.Parse("docker://sqlserver/2019-latest/foo")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "sqlserver",
setup: []string{"CREATE DATABASE [foo]"},
Image: "mcr.microsoft.com/mssql/server:2019-latest",
Database: "foo",
User: url.UserPassword("sa", passSQLServer),
Port: "1433",
Out: io.Discard,
Env: []string{
"ACCEPT_EULA=Y",
"MSSQL_PID=Developer",
"MSSQL_SA_PASSWORD=" + passSQLServer,
},
}, cfg)
// Azure SQL Edge
u, err = url.Parse("docker+sqlserver://mcr.microsoft.com/azure-sql-edge:1.0.7/foo")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "sqlserver",
setup: []string{"CREATE DATABASE [foo]"},
Image: "mcr.microsoft.com/azure-sql-edge:1.0.7",
Database: "foo",
User: url.UserPassword("sa", passSQLServer),
Port: "1433",
Out: io.Discard,
Env: []string{
"ACCEPT_EULA=Y",
"MSSQL_PID=Developer",
"MSSQL_SA_PASSWORD=" + passSQLServer,
},
}, cfg)
// ClickHouse
u, err = url.Parse("docker://clickhouse")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "clickhouse",
Image: "clickhouse/clickhouse-server",
Env: []string{"CLICKHOUSE_PASSWORD=pass"},
User: url.UserPassword("default", pass),
Port: "9000",
Out: io.Discard,
}, cfg)
// ClickHouse with tag
u, err = url.Parse("docker://clickhouse/23.11")
require.NoError(t, err)
cfg, err = FromURL(u)
require.NoError(t, err)
require.Equal(t, &Config{
driver: "clickhouse",
Image: "clickhouse/clickhouse-server:23.11",
User: url.UserPassword("default", pass),
Env: []string{"CLICKHOUSE_PASSWORD=pass"},
Port: "9000",
Out: io.Discard,
}, cfg)
}
func TestFromURL_CustomImage(t *testing.T) {
for _, tt := range []struct {
url, image, db, dialect string
}{
// PostgreSQL (local and official images).
{
url: "docker+postgres://local",
image: "local",
db: "postgres",
dialect: "postgres",
},
{
url: "docker+postgres://_/local/dev",
image: "local",
db: "dev",
dialect: "postgres",
},
{
url: "docker+postgres:///local:tag/dev",
image: "local:tag",
db: "dev",
dialect: "postgres",
},
{
url: "docker+postgres://postgres",
image: "postgres",
db: "postgres",
dialect: "postgres",
},
{
url: "docker+postgres://_/postgres/dev",
image: "postgres",
db: "dev",
dialect: "postgres",
},
{
url: "docker+postgres:///postgres:16/dev",
image: "postgres:16",
db: "dev",
dialect: "postgres",
},
// User images.
{
url: "docker+postgres://postgis/postgis:16",
image: "postgis/postgis:16",
db: "postgres",
dialect: "postgres",
},
{
url: "docker+postgres://postgis/postgis:16/dev",
image: "postgis/postgis:16",
db: "dev",
dialect: "postgres",
},
{
url: "docker+postgres://ghcr.io/namespace/image:tag",
image: "ghcr.io/namespace/image:tag",
db: "postgres",
dialect: "postgres",
},
{
url: "docker+postgres://ghcr.io/namespace/image:tag/dev",
image: "ghcr.io/namespace/image:tag",
db: "dev",
dialect: "postgres",
},
// MySQL.
{
url: "docker+mysql://local",
image: "local",
dialect: "mysql",
},
{
url: "docker+mysql:///local/dev",
image: "local",
db: "dev",
dialect: "mysql",
},
{
url: "docker+mysql://user/image",
image: "user/image",
dialect: "mysql",
},
{
url: "docker+mysql://user/image:tag/dev",
image: "user/image:tag",
db: "dev",
dialect: "mysql",
},
{
url: "docker+mysql://_/mariadb:latest/dev",
image: "mariadb:latest",
db: "dev",
dialect: "mysql",
},
// SQL Server.
{
url: "docker+sqlserver://mcr.microsoft.com/mssql/server:2022-latest",
image: "mcr.microsoft.com/mssql/server:2022-latest",
db: "master",
dialect: "sqlserver",
},
{
url: "docker+sqlserver://mcr.microsoft.com/mssql/server:2022-latest/dev",
image: "mcr.microsoft.com/mssql/server:2022-latest",
db: "dev",
dialect: "sqlserver",
},
{
url: "docker+sqlserver://mcr.microsoft.com/mssql/server:latest",
image: "mcr.microsoft.com/mssql/server:latest",
db: "master",
dialect: "sqlserver",
},
// ClickHouse.
{
url: "docker+clickhouse://clickhouse/clickhouse-server:23.11",
image: "clickhouse/clickhouse-server:23.11",
dialect: "clickhouse",
},
{
url: "docker+clickhouse://clickhouse/clickhouse-server:23.11/dev",
image: "clickhouse/clickhouse-server:23.11",
db: "dev",
dialect: "clickhouse",
},
} {
u, err := url.Parse(tt.url)
require.NoError(t, err)
cfg, err := FromURL(u)
require.NoError(t, err)
require.Equal(t, tt.image, cfg.Image)
require.Equal(t, tt.db, cfg.Database)
require.Equal(t, tt.dialect, cfg.driver)
}
}
func TestImageURL(t *testing.T) {
for img, u := range map[string]string{
"postgres:15": "docker+postgres://_/postgres:15",
"postgres": "docker+postgres://_/postgres",
"postgis/postgis:14-3.4": "docker+postgres://postgis/postgis:14-3.4",
"ghcr.io/namespace/postgres:tag": "docker+postgres://ghcr.io/namespace/postgres:tag",
} {
got, err := ImageURL(DriverPostgres, img)
require.NoError(t, err)
require.Equal(t, u, got.String())
}
for img, u := range map[string]string{
"mcr.microsoft.com/azure-sql-edge:1.0.7": "docker+sqlserver://mcr.microsoft.com/azure-sql-edge:1.0.7",
"mcr.microsoft.com/mssql/server:2022-latest": "docker+sqlserver://mcr.microsoft.com/mssql/server:2022-latest",
} {
got, err := ImageURL(DriverSQLServer, img)
require.NoError(t, err)
require.Equal(t, u, got.String())
}
}
func TestContainerURL(t *testing.T) {
c := &Container{
Config: Config{
driver: "postgres",
User: url.UserPassword("postgres", "pass"),
},
Port: "5432",
}
u, err := c.URL()
require.NoError(t, err)
require.Equal(t, "postgres://postgres:pass@localhost:5432/?sslmode=disable", u.String())
// With DOCKER_HOST
t.Setenv("DOCKER_HOST", "tcp://host.docker.internal:2375")
u, err = c.URL()
require.NoError(t, err)
require.Equal(t, "postgres://postgres:pass@host.docker.internal:5432/?sslmode=disable", u.String())
}
================================================
FILE: cmd/atlas/internal/migrate/ent/client.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package ent
import (
"context"
"errors"
"fmt"
"log"
"reflect"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/migrate"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"entgo.io/ent"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql"
stdsql "database/sql"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/internal"
)
// Client is the client that holds all ent builders.
type Client struct {
config
// Schema is the client for creating, migrating and dropping schema.
Schema *migrate.Schema
// Revision is the client for interacting with the Revision builders.
Revision *RevisionClient
}
// NewClient creates a new client configured with the given options.
func NewClient(opts ...Option) *Client {
client := &Client{config: newConfig(opts...)}
client.init()
return client
}
func (c *Client) init() {
c.Schema = migrate.NewSchema(c.driver)
c.Revision = NewRevisionClient(c.config)
}
type (
// config is the configuration for the client and its builder.
config struct {
// driver used for executing database requests.
driver dialect.Driver
// debug enable a debug logging.
debug bool
// log used for logging on debug mode.
log func(...any)
// hooks to execute on mutations.
hooks *hooks
// interceptors to execute on queries.
inters *inters
// schemaConfig contains alternative names for all tables.
schemaConfig SchemaConfig
}
// Option function to configure the client.
Option func(*config)
)
// newConfig creates a new config for the client.
func newConfig(opts ...Option) config {
cfg := config{log: log.Println, hooks: &hooks{}, inters: &inters{}}
cfg.options(opts...)
return cfg
}
// options applies the options on the config object.
func (c *config) options(opts ...Option) {
for _, opt := range opts {
opt(c)
}
if c.debug {
c.driver = dialect.Debug(c.driver, c.log)
}
}
// Debug enables debug logging on the ent.Driver.
func Debug() Option {
return func(c *config) {
c.debug = true
}
}
// Log sets the logging function for debug mode.
func Log(fn func(...any)) Option {
return func(c *config) {
c.log = fn
}
}
// Driver configures the client driver.
func Driver(driver dialect.Driver) Option {
return func(c *config) {
c.driver = driver
}
}
// Open opens a database/sql.DB specified by the driver name and
// the data source name, and returns a new client attached to it.
// Optional parameters can be added for configuring the client.
func Open(driverName, dataSourceName string, options ...Option) (*Client, error) {
switch driverName {
case dialect.MySQL, dialect.Postgres, dialect.SQLite:
drv, err := sql.Open(driverName, dataSourceName)
if err != nil {
return nil, err
}
return NewClient(append(options, Driver(drv))...), nil
default:
return nil, fmt.Errorf("unsupported driver: %q", driverName)
}
}
// ErrTxStarted is returned when trying to start a new transaction from a transactional client.
var ErrTxStarted = errors.New("ent: cannot start a transaction within a transaction")
// Tx returns a new transactional client. The provided context
// is used until the transaction is committed or rolled back.
func (c *Client) Tx(ctx context.Context) (*Tx, error) {
if _, ok := c.driver.(*txDriver); ok {
return nil, ErrTxStarted
}
tx, err := newTx(ctx, c.driver)
if err != nil {
return nil, fmt.Errorf("ent: starting a transaction: %w", err)
}
cfg := c.config
cfg.driver = tx
return &Tx{
ctx: ctx,
config: cfg,
Revision: NewRevisionClient(cfg),
}, nil
}
// BeginTx returns a transactional client with specified options.
func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
if _, ok := c.driver.(*txDriver); ok {
return nil, errors.New("ent: cannot start a transaction within a transaction")
}
tx, err := c.driver.(interface {
BeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error)
}).BeginTx(ctx, opts)
if err != nil {
return nil, fmt.Errorf("ent: starting a transaction: %w", err)
}
cfg := c.config
cfg.driver = &txDriver{tx: tx, drv: c.driver}
return &Tx{
ctx: ctx,
config: cfg,
Revision: NewRevisionClient(cfg),
}, nil
}
// Debug returns a new debug-client. It's used to get verbose logging on specific operations.
//
// client.Debug().
// Revision.
// Query().
// Count(ctx)
func (c *Client) Debug() *Client {
if c.debug {
return c
}
cfg := c.config
cfg.driver = dialect.Debug(c.driver, c.log)
client := &Client{config: cfg}
client.init()
return client
}
// Close closes the database connection and prevents new queries from starting.
func (c *Client) Close() error {
return c.driver.Close()
}
// Use adds the mutation hooks to all the entity clients.
// In order to add hooks to a specific client, call: `client.Node.Use(...)`.
func (c *Client) Use(hooks ...Hook) {
c.Revision.Use(hooks...)
}
// Intercept adds the query interceptors to all the entity clients.
// In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`.
func (c *Client) Intercept(interceptors ...Interceptor) {
c.Revision.Intercept(interceptors...)
}
// Mutate implements the ent.Mutator interface.
func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
switch m := m.(type) {
case *RevisionMutation:
return c.Revision.mutate(ctx, m)
default:
return nil, fmt.Errorf("ent: unknown mutation type %T", m)
}
}
// RevisionClient is a client for the Revision schema.
type RevisionClient struct {
config
}
// NewRevisionClient returns a client for the Revision from the given config.
func NewRevisionClient(c config) *RevisionClient {
return &RevisionClient{config: c}
}
// Use adds a list of mutation hooks to the hooks stack.
// A call to `Use(f, g, h)` equals to `revision.Hooks(f(g(h())))`.
func (c *RevisionClient) Use(hooks ...Hook) {
c.hooks.Revision = append(c.hooks.Revision, hooks...)
}
// Intercept adds a list of query interceptors to the interceptors stack.
// A call to `Intercept(f, g, h)` equals to `revision.Intercept(f(g(h())))`.
func (c *RevisionClient) Intercept(interceptors ...Interceptor) {
c.inters.Revision = append(c.inters.Revision, interceptors...)
}
// Create returns a builder for creating a Revision entity.
func (c *RevisionClient) Create() *RevisionCreate {
mutation := newRevisionMutation(c.config, OpCreate)
return &RevisionCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// CreateBulk returns a builder for creating a bulk of Revision entities.
func (c *RevisionClient) CreateBulk(builders ...*RevisionCreate) *RevisionCreateBulk {
return &RevisionCreateBulk{config: c.config, builders: builders}
}
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *RevisionClient) MapCreateBulk(slice any, setFunc func(*RevisionCreate, int)) *RevisionCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &RevisionCreateBulk{err: fmt.Errorf("calling to RevisionClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*RevisionCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &RevisionCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for Revision.
func (c *RevisionClient) Update() *RevisionUpdate {
mutation := newRevisionMutation(c.config, OpUpdate)
return &RevisionUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOne returns an update builder for the given entity.
func (c *RevisionClient) UpdateOne(_m *Revision) *RevisionUpdateOne {
mutation := newRevisionMutation(c.config, OpUpdateOne, withRevision(_m))
return &RevisionUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOneID returns an update builder for the given id.
func (c *RevisionClient) UpdateOneID(id string) *RevisionUpdateOne {
mutation := newRevisionMutation(c.config, OpUpdateOne, withRevisionID(id))
return &RevisionUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// Delete returns a delete builder for Revision.
func (c *RevisionClient) Delete() *RevisionDelete {
mutation := newRevisionMutation(c.config, OpDelete)
return &RevisionDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// DeleteOne returns a builder for deleting the given entity.
func (c *RevisionClient) DeleteOne(_m *Revision) *RevisionDeleteOne {
return c.DeleteOneID(_m.ID)
}
// DeleteOneID returns a builder for deleting the given entity by its id.
func (c *RevisionClient) DeleteOneID(id string) *RevisionDeleteOne {
builder := c.Delete().Where(revision.ID(id))
builder.mutation.id = &id
builder.mutation.op = OpDeleteOne
return &RevisionDeleteOne{builder}
}
// Query returns a query builder for Revision.
func (c *RevisionClient) Query() *RevisionQuery {
return &RevisionQuery{
config: c.config,
ctx: &QueryContext{Type: TypeRevision},
inters: c.Interceptors(),
}
}
// Get returns a Revision entity by its id.
func (c *RevisionClient) Get(ctx context.Context, id string) (*Revision, error) {
return c.Query().Where(revision.ID(id)).Only(ctx)
}
// GetX is like Get, but panics if an error occurs.
func (c *RevisionClient) GetX(ctx context.Context, id string) *Revision {
obj, err := c.Get(ctx, id)
if err != nil {
panic(err)
}
return obj
}
// Hooks returns the client hooks.
func (c *RevisionClient) Hooks() []Hook {
return c.hooks.Revision
}
// Interceptors returns the client interceptors.
func (c *RevisionClient) Interceptors() []Interceptor {
return c.inters.Revision
}
func (c *RevisionClient) mutate(ctx context.Context, m *RevisionMutation) (Value, error) {
switch m.Op() {
case OpCreate:
return (&RevisionCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdate:
return (&RevisionUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdateOne:
return (&RevisionUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpDelete, OpDeleteOne:
return (&RevisionDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
default:
return nil, fmt.Errorf("ent: unknown Revision mutation op: %q", m.Op())
}
}
// hooks and interceptors per client, for fast access.
type (
hooks struct {
Revision []ent.Hook
}
inters struct {
Revision []ent.Interceptor
}
)
// SchemaConfig represents alternative schema names for all tables
// that can be passed at runtime.
type SchemaConfig = internal.SchemaConfig
// AlternateSchemas allows alternate schema names to be
// passed into ent operations.
func AlternateSchema(schemaConfig SchemaConfig) Option {
return func(c *config) {
c.schemaConfig = schemaConfig
}
}
// ExecContext allows calling the underlying ExecContext method of the driver if it is supported by it.
// See, database/sql#DB.ExecContext for more information.
func (c *config) ExecContext(ctx context.Context, query string, args ...any) (stdsql.Result, error) {
ex, ok := c.driver.(interface {
ExecContext(context.Context, string, ...any) (stdsql.Result, error)
})
if !ok {
return nil, fmt.Errorf("Driver.ExecContext is not supported")
}
return ex.ExecContext(ctx, query, args...)
}
// QueryContext allows calling the underlying QueryContext method of the driver if it is supported by it.
// See, database/sql#DB.QueryContext for more information.
func (c *config) QueryContext(ctx context.Context, query string, args ...any) (*stdsql.Rows, error) {
q, ok := c.driver.(interface {
QueryContext(context.Context, string, ...any) (*stdsql.Rows, error)
})
if !ok {
return nil, fmt.Errorf("Driver.QueryContext is not supported")
}
return q.QueryContext(ctx, query, args...)
}
================================================
FILE: cmd/atlas/internal/migrate/ent/convert.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package ent
import "ariga.io/atlas/sql/migrate"
// SetRevision takes the values for each field from the given migrate.Revision.
func (rc *RevisionCreate) SetRevision(rev *migrate.Revision) *RevisionCreate {
rc.SetID(rev.Version)
rc.SetDescription(rev.Description)
rc.SetType(rev.Type)
rc.SetApplied(rev.Applied)
rc.SetTotal(rev.Total)
rc.SetExecutedAt(rev.ExecutedAt)
rc.SetExecutionTime(rev.ExecutionTime)
rc.SetError(rev.Error)
rc.SetErrorStmt(rev.ErrorStmt)
rc.SetHash(rev.Hash)
rc.SetPartialHashes(rev.PartialHashes)
rc.SetOperatorVersion(rev.OperatorVersion)
return rc
}
// AtlasRevision returns an migrate.Revision from the current Revision.
func (_m *Revision) AtlasRevision() *migrate.Revision {
return &migrate.Revision{
Version: _m.ID,
Description: _m.Description,
Type: _m.Type,
Applied: _m.Applied,
Total: _m.Total,
ExecutedAt: _m.ExecutedAt,
ExecutionTime: _m.ExecutionTime,
Error: _m.Error,
ErrorStmt: _m.ErrorStmt,
Hash: _m.Hash,
PartialHashes: _m.PartialHashes,
OperatorVersion: _m.OperatorVersion,
}
}
================================================
FILE: cmd/atlas/internal/migrate/ent/ent.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package ent
import (
"context"
"errors"
"fmt"
"reflect"
"sync"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
)
// ent aliases to avoid import conflicts in user's code.
type (
Op = ent.Op
Hook = ent.Hook
Value = ent.Value
Query = ent.Query
QueryContext = ent.QueryContext
Querier = ent.Querier
QuerierFunc = ent.QuerierFunc
Interceptor = ent.Interceptor
InterceptFunc = ent.InterceptFunc
Traverser = ent.Traverser
TraverseFunc = ent.TraverseFunc
Policy = ent.Policy
Mutator = ent.Mutator
Mutation = ent.Mutation
MutateFunc = ent.MutateFunc
)
type clientCtxKey struct{}
// FromContext returns a Client stored inside a context, or nil if there isn't one.
func FromContext(ctx context.Context) *Client {
c, _ := ctx.Value(clientCtxKey{}).(*Client)
return c
}
// NewContext returns a new context with the given Client attached.
func NewContext(parent context.Context, c *Client) context.Context {
return context.WithValue(parent, clientCtxKey{}, c)
}
type txCtxKey struct{}
// TxFromContext returns a Tx stored inside a context, or nil if there isn't one.
func TxFromContext(ctx context.Context) *Tx {
tx, _ := ctx.Value(txCtxKey{}).(*Tx)
return tx
}
// NewTxContext returns a new context with the given Tx attached.
func NewTxContext(parent context.Context, tx *Tx) context.Context {
return context.WithValue(parent, txCtxKey{}, tx)
}
// OrderFunc applies an ordering on the sql selector.
// Deprecated: Use Asc/Desc functions or the package builders instead.
type OrderFunc func(*sql.Selector)
var (
initCheck sync.Once
columnCheck sql.ColumnCheck
)
// checkColumn checks if the column exists in the given table.
func checkColumn(t, c string) error {
initCheck.Do(func() {
columnCheck = sql.NewColumnCheck(map[string]func(string) bool{
revision.Table: revision.ValidColumn,
})
})
return columnCheck(t, c)
}
// Asc applies the given fields in ASC order.
func Asc(fields ...string) func(*sql.Selector) {
return func(s *sql.Selector) {
for _, f := range fields {
if err := checkColumn(s.TableName(), f); err != nil {
s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)})
}
s.OrderBy(sql.Asc(s.C(f)))
}
}
}
// Desc applies the given fields in DESC order.
func Desc(fields ...string) func(*sql.Selector) {
return func(s *sql.Selector) {
for _, f := range fields {
if err := checkColumn(s.TableName(), f); err != nil {
s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)})
}
s.OrderBy(sql.Desc(s.C(f)))
}
}
}
// AggregateFunc applies an aggregation step on the group-by traversal/selector.
type AggregateFunc func(*sql.Selector) string
// As is a pseudo aggregation function for renaming another other functions with custom names. For example:
//
// GroupBy(field1, field2).
// Aggregate(ent.As(ent.Sum(field1), "sum_field1"), (ent.As(ent.Sum(field2), "sum_field2")).
// Scan(ctx, &v)
func As(fn AggregateFunc, end string) AggregateFunc {
return func(s *sql.Selector) string {
return sql.As(fn(s), end)
}
}
// Count applies the "count" aggregation function on each group.
func Count() AggregateFunc {
return func(s *sql.Selector) string {
return sql.Count("*")
}
}
// Max applies the "max" aggregation function on the given field of each group.
func Max(field string) AggregateFunc {
return func(s *sql.Selector) string {
if err := checkColumn(s.TableName(), field); err != nil {
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
return ""
}
return sql.Max(s.C(field))
}
}
// Mean applies the "mean" aggregation function on the given field of each group.
func Mean(field string) AggregateFunc {
return func(s *sql.Selector) string {
if err := checkColumn(s.TableName(), field); err != nil {
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
return ""
}
return sql.Avg(s.C(field))
}
}
// Min applies the "min" aggregation function on the given field of each group.
func Min(field string) AggregateFunc {
return func(s *sql.Selector) string {
if err := checkColumn(s.TableName(), field); err != nil {
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
return ""
}
return sql.Min(s.C(field))
}
}
// Sum applies the "sum" aggregation function on the given field of each group.
func Sum(field string) AggregateFunc {
return func(s *sql.Selector) string {
if err := checkColumn(s.TableName(), field); err != nil {
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
return ""
}
return sql.Sum(s.C(field))
}
}
// ValidationError returns when validating a field or edge fails.
type ValidationError struct {
Name string // Field or edge name.
err error
}
// Error implements the error interface.
func (e *ValidationError) Error() string {
return e.err.Error()
}
// Unwrap implements the errors.Wrapper interface.
func (e *ValidationError) Unwrap() error {
return e.err
}
// IsValidationError returns a boolean indicating whether the error is a validation error.
func IsValidationError(err error) bool {
if err == nil {
return false
}
var e *ValidationError
return errors.As(err, &e)
}
// NotFoundError returns when trying to fetch a specific entity and it was not found in the database.
type NotFoundError struct {
label string
}
// Error implements the error interface.
func (e *NotFoundError) Error() string {
return "ent: " + e.label + " not found"
}
// IsNotFound returns a boolean indicating whether the error is a not found error.
func IsNotFound(err error) bool {
if err == nil {
return false
}
var e *NotFoundError
return errors.As(err, &e)
}
// MaskNotFound masks not found error.
func MaskNotFound(err error) error {
if IsNotFound(err) {
return nil
}
return err
}
// NotSingularError returns when trying to fetch a singular entity and more then one was found in the database.
type NotSingularError struct {
label string
}
// Error implements the error interface.
func (e *NotSingularError) Error() string {
return "ent: " + e.label + " not singular"
}
// IsNotSingular returns a boolean indicating whether the error is a not singular error.
func IsNotSingular(err error) bool {
if err == nil {
return false
}
var e *NotSingularError
return errors.As(err, &e)
}
// NotLoadedError returns when trying to get a node that was not loaded by the query.
type NotLoadedError struct {
edge string
}
// Error implements the error interface.
func (e *NotLoadedError) Error() string {
return "ent: " + e.edge + " edge was not loaded"
}
// IsNotLoaded returns a boolean indicating whether the error is a not loaded error.
func IsNotLoaded(err error) bool {
if err == nil {
return false
}
var e *NotLoadedError
return errors.As(err, &e)
}
// ConstraintError returns when trying to create/update one or more entities and
// one or more of their constraints failed. For example, violation of edge or
// field uniqueness.
type ConstraintError struct {
msg string
wrap error
}
// Error implements the error interface.
func (e ConstraintError) Error() string {
return "ent: constraint failed: " + e.msg
}
// Unwrap implements the errors.Wrapper interface.
func (e *ConstraintError) Unwrap() error {
return e.wrap
}
// IsConstraintError returns a boolean indicating whether the error is a constraint failure.
func IsConstraintError(err error) bool {
if err == nil {
return false
}
var e *ConstraintError
return errors.As(err, &e)
}
// selector embedded by the different Select/GroupBy builders.
type selector struct {
label string
flds *[]string
fns []AggregateFunc
scan func(context.Context, any) error
}
// ScanX is like Scan, but panics if an error occurs.
func (s *selector) ScanX(ctx context.Context, v any) {
if err := s.scan(ctx, v); err != nil {
panic(err)
}
}
// Strings returns list of strings from a selector. It is only allowed when selecting one field.
func (s *selector) Strings(ctx context.Context) ([]string, error) {
if len(*s.flds) > 1 {
return nil, errors.New("ent: Strings is not achievable when selecting more than 1 field")
}
var v []string
if err := s.scan(ctx, &v); err != nil {
return nil, err
}
return v, nil
}
// StringsX is like Strings, but panics if an error occurs.
func (s *selector) StringsX(ctx context.Context) []string {
v, err := s.Strings(ctx)
if err != nil {
panic(err)
}
return v
}
// String returns a single string from a selector. It is only allowed when selecting one field.
func (s *selector) String(ctx context.Context) (_ string, err error) {
var v []string
if v, err = s.Strings(ctx); err != nil {
return
}
switch len(v) {
case 1:
return v[0], nil
case 0:
err = &NotFoundError{s.label}
default:
err = fmt.Errorf("ent: Strings returned %d results when one was expected", len(v))
}
return
}
// StringX is like String, but panics if an error occurs.
func (s *selector) StringX(ctx context.Context) string {
v, err := s.String(ctx)
if err != nil {
panic(err)
}
return v
}
// Ints returns list of ints from a selector. It is only allowed when selecting one field.
func (s *selector) Ints(ctx context.Context) ([]int, error) {
if len(*s.flds) > 1 {
return nil, errors.New("ent: Ints is not achievable when selecting more than 1 field")
}
var v []int
if err := s.scan(ctx, &v); err != nil {
return nil, err
}
return v, nil
}
// IntsX is like Ints, but panics if an error occurs.
func (s *selector) IntsX(ctx context.Context) []int {
v, err := s.Ints(ctx)
if err != nil {
panic(err)
}
return v
}
// Int returns a single int from a selector. It is only allowed when selecting one field.
func (s *selector) Int(ctx context.Context) (_ int, err error) {
var v []int
if v, err = s.Ints(ctx); err != nil {
return
}
switch len(v) {
case 1:
return v[0], nil
case 0:
err = &NotFoundError{s.label}
default:
err = fmt.Errorf("ent: Ints returned %d results when one was expected", len(v))
}
return
}
// IntX is like Int, but panics if an error occurs.
func (s *selector) IntX(ctx context.Context) int {
v, err := s.Int(ctx)
if err != nil {
panic(err)
}
return v
}
// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
func (s *selector) Float64s(ctx context.Context) ([]float64, error) {
if len(*s.flds) > 1 {
return nil, errors.New("ent: Float64s is not achievable when selecting more than 1 field")
}
var v []float64
if err := s.scan(ctx, &v); err != nil {
return nil, err
}
return v, nil
}
// Float64sX is like Float64s, but panics if an error occurs.
func (s *selector) Float64sX(ctx context.Context) []float64 {
v, err := s.Float64s(ctx)
if err != nil {
panic(err)
}
return v
}
// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
func (s *selector) Float64(ctx context.Context) (_ float64, err error) {
var v []float64
if v, err = s.Float64s(ctx); err != nil {
return
}
switch len(v) {
case 1:
return v[0], nil
case 0:
err = &NotFoundError{s.label}
default:
err = fmt.Errorf("ent: Float64s returned %d results when one was expected", len(v))
}
return
}
// Float64X is like Float64, but panics if an error occurs.
func (s *selector) Float64X(ctx context.Context) float64 {
v, err := s.Float64(ctx)
if err != nil {
panic(err)
}
return v
}
// Bools returns list of bools from a selector. It is only allowed when selecting one field.
func (s *selector) Bools(ctx context.Context) ([]bool, error) {
if len(*s.flds) > 1 {
return nil, errors.New("ent: Bools is not achievable when selecting more than 1 field")
}
var v []bool
if err := s.scan(ctx, &v); err != nil {
return nil, err
}
return v, nil
}
// BoolsX is like Bools, but panics if an error occurs.
func (s *selector) BoolsX(ctx context.Context) []bool {
v, err := s.Bools(ctx)
if err != nil {
panic(err)
}
return v
}
// Bool returns a single bool from a selector. It is only allowed when selecting one field.
func (s *selector) Bool(ctx context.Context) (_ bool, err error) {
var v []bool
if v, err = s.Bools(ctx); err != nil {
return
}
switch len(v) {
case 1:
return v[0], nil
case 0:
err = &NotFoundError{s.label}
default:
err = fmt.Errorf("ent: Bools returned %d results when one was expected", len(v))
}
return
}
// BoolX is like Bool, but panics if an error occurs.
func (s *selector) BoolX(ctx context.Context) bool {
v, err := s.Bool(ctx)
if err != nil {
panic(err)
}
return v
}
// withHooks invokes the builder operation with the given hooks, if any.
func withHooks[V Value, M any, PM interface {
*M
Mutation
}](ctx context.Context, exec func(context.Context) (V, error), mutation PM, hooks []Hook) (value V, err error) {
if len(hooks) == 0 {
return exec(ctx)
}
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutationT, ok := any(m).(PM)
if !ok {
return nil, fmt.Errorf("unexpected mutation type %T", m)
}
// Set the mutation to the builder.
*mutation = *mutationT
return exec(ctx)
})
for i := len(hooks) - 1; i >= 0; i-- {
if hooks[i] == nil {
return value, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
}
mut = hooks[i](mut)
}
v, err := mut.Mutate(ctx, mutation)
if err != nil {
return value, err
}
nv, ok := v.(V)
if !ok {
return value, fmt.Errorf("unexpected node type %T returned from %T", v, mutation)
}
return nv, nil
}
// setContextOp returns a new context with the given QueryContext attached (including its op) in case it does not exist.
func setContextOp(ctx context.Context, qc *QueryContext, op string) context.Context {
if ent.QueryFromContext(ctx) == nil {
qc.Op = op
ctx = ent.NewQueryContext(ctx, qc)
}
return ctx
}
func querierAll[V Value, Q interface {
sqlAll(context.Context, ...queryHook) (V, error)
}]() Querier {
return QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
query, ok := q.(Q)
if !ok {
return nil, fmt.Errorf("unexpected query type %T", q)
}
return query.sqlAll(ctx)
})
}
func querierCount[Q interface {
sqlCount(context.Context) (int, error)
}]() Querier {
return QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
query, ok := q.(Q)
if !ok {
return nil, fmt.Errorf("unexpected query type %T", q)
}
return query.sqlCount(ctx)
})
}
func withInterceptors[V Value](ctx context.Context, q Query, qr Querier, inters []Interceptor) (v V, err error) {
for i := len(inters) - 1; i >= 0; i-- {
qr = inters[i].Intercept(qr)
}
rv, err := qr.Query(ctx, q)
if err != nil {
return v, err
}
vt, ok := rv.(V)
if !ok {
return v, fmt.Errorf("unexpected type %T returned from %T. expected type: %T", vt, q, v)
}
return vt, nil
}
func scanWithInterceptors[Q1 ent.Query, Q2 interface {
sqlScan(context.Context, Q1, any) error
}](ctx context.Context, rootQuery Q1, selectOrGroup Q2, inters []Interceptor, v any) error {
rv := reflect.ValueOf(v)
var qr Querier = QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
query, ok := q.(Q1)
if !ok {
return nil, fmt.Errorf("unexpected query type %T", q)
}
if err := selectOrGroup.sqlScan(ctx, query, v); err != nil {
return nil, err
}
if k := rv.Kind(); k == reflect.Pointer && rv.Elem().CanInterface() {
return rv.Elem().Interface(), nil
}
return v, nil
})
for i := len(inters) - 1; i >= 0; i-- {
qr = inters[i].Intercept(qr)
}
vv, err := qr.Query(ctx, rootQuery)
if err != nil {
return err
}
switch rv2 := reflect.ValueOf(vv); {
case rv.IsNil(), rv2.IsNil(), rv.Kind() != reflect.Pointer:
case rv.Type() == rv2.Type():
rv.Elem().Set(rv2.Elem())
case rv.Elem().Type() == rv2.Type():
rv.Elem().Set(rv2)
}
return nil
}
// queryHook describes an internal hook for the different sqlAll methods.
type queryHook func(context.Context, *sqlgraph.QuerySpec)
================================================
FILE: cmd/atlas/internal/migrate/ent/entc.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build ignore
package main
import (
"log"
"entgo.io/ent/entc"
"entgo.io/ent/entc/gen"
)
func main() {
err := entc.Generate("./schema", &gen.Config{
Header: `// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
`,
Features: []gen.Feature{
gen.FeatureUpsert,
gen.FeatureExecQuery,
gen.FeatureSchemaConfig,
},
}, entc.TemplateDir("template"))
if err != nil {
log.Fatalf("running ent codegen: %v", err)
}
}
================================================
FILE: cmd/atlas/internal/migrate/ent/enttest/enttest.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package enttest
import (
"context"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent"
// required by schema hooks.
_ "ariga.io/atlas/cmd/atlas/internal/migrate/ent/runtime"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/migrate"
"entgo.io/ent/dialect/sql/schema"
)
type (
// TestingT is the interface that is shared between
// testing.T and testing.B and used by enttest.
TestingT interface {
FailNow()
Error(...any)
}
// Option configures client creation.
Option func(*options)
options struct {
opts []ent.Option
migrateOpts []schema.MigrateOption
}
)
// WithOptions forwards options to client creation.
func WithOptions(opts ...ent.Option) Option {
return func(o *options) {
o.opts = append(o.opts, opts...)
}
}
// WithMigrateOptions forwards options to auto migration.
func WithMigrateOptions(opts ...schema.MigrateOption) Option {
return func(o *options) {
o.migrateOpts = append(o.migrateOpts, opts...)
}
}
func newOptions(opts []Option) *options {
o := &options{}
for _, opt := range opts {
opt(o)
}
return o
}
// Open calls ent.Open and auto-run migration.
func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client {
o := newOptions(opts)
c, err := ent.Open(driverName, dataSourceName, o.opts...)
if err != nil {
t.Error(err)
t.FailNow()
}
migrateSchema(t, c, o)
return c
}
// NewClient calls ent.NewClient and auto-run migration.
func NewClient(t TestingT, opts ...Option) *ent.Client {
o := newOptions(opts)
c := ent.NewClient(o.opts...)
migrateSchema(t, c, o)
return c
}
func migrateSchema(t TestingT, c *ent.Client, o *options) {
tables, err := schema.CopyTables(migrate.Tables)
if err != nil {
t.Error(err)
t.FailNow()
}
if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil {
t.Error(err)
t.FailNow()
}
}
================================================
FILE: cmd/atlas/internal/migrate/ent/generate.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package ent
//go:generate go run -mod=mod entc.go
================================================
FILE: cmd/atlas/internal/migrate/ent/hook/hook.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package hook
import (
"context"
"fmt"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent"
)
// The RevisionFunc type is an adapter to allow the use of ordinary
// function as Revision mutator.
type RevisionFunc func(context.Context, *ent.RevisionMutation) (ent.Value, error)
// Mutate calls f(ctx, m).
func (f RevisionFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
if mv, ok := m.(*ent.RevisionMutation); ok {
return f(ctx, mv)
}
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.RevisionMutation", m)
}
// Condition is a hook condition function.
type Condition func(context.Context, ent.Mutation) bool
// And groups conditions with the AND operator.
func And(first, second Condition, rest ...Condition) Condition {
return func(ctx context.Context, m ent.Mutation) bool {
if !first(ctx, m) || !second(ctx, m) {
return false
}
for _, cond := range rest {
if !cond(ctx, m) {
return false
}
}
return true
}
}
// Or groups conditions with the OR operator.
func Or(first, second Condition, rest ...Condition) Condition {
return func(ctx context.Context, m ent.Mutation) bool {
if first(ctx, m) || second(ctx, m) {
return true
}
for _, cond := range rest {
if cond(ctx, m) {
return true
}
}
return false
}
}
// Not negates a given condition.
func Not(cond Condition) Condition {
return func(ctx context.Context, m ent.Mutation) bool {
return !cond(ctx, m)
}
}
// HasOp is a condition testing mutation operation.
func HasOp(op ent.Op) Condition {
return func(_ context.Context, m ent.Mutation) bool {
return m.Op().Is(op)
}
}
// HasAddedFields is a condition validating `.AddedField` on fields.
func HasAddedFields(field string, fields ...string) Condition {
return func(_ context.Context, m ent.Mutation) bool {
if _, exists := m.AddedField(field); !exists {
return false
}
for _, field := range fields {
if _, exists := m.AddedField(field); !exists {
return false
}
}
return true
}
}
// HasClearedFields is a condition validating `.FieldCleared` on fields.
func HasClearedFields(field string, fields ...string) Condition {
return func(_ context.Context, m ent.Mutation) bool {
if exists := m.FieldCleared(field); !exists {
return false
}
for _, field := range fields {
if exists := m.FieldCleared(field); !exists {
return false
}
}
return true
}
}
// HasFields is a condition validating `.Field` on fields.
func HasFields(field string, fields ...string) Condition {
return func(_ context.Context, m ent.Mutation) bool {
if _, exists := m.Field(field); !exists {
return false
}
for _, field := range fields {
if _, exists := m.Field(field); !exists {
return false
}
}
return true
}
}
// If executes the given hook under condition.
//
// hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...)))
func If(hk ent.Hook, cond Condition) ent.Hook {
return func(next ent.Mutator) ent.Mutator {
return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) {
if cond(ctx, m) {
return hk(next).Mutate(ctx, m)
}
return next.Mutate(ctx, m)
})
}
}
// On executes the given hook only for the given operation.
//
// hook.On(Log, ent.Delete|ent.Create)
func On(hk ent.Hook, op ent.Op) ent.Hook {
return If(hk, HasOp(op))
}
// Unless skips the given hook only for the given operation.
//
// hook.Unless(Log, ent.Update|ent.UpdateOne)
func Unless(hk ent.Hook, op ent.Op) ent.Hook {
return If(hk, Not(HasOp(op)))
}
// FixedError is a hook returning a fixed error.
func FixedError(err error) ent.Hook {
return func(ent.Mutator) ent.Mutator {
return ent.MutateFunc(func(context.Context, ent.Mutation) (ent.Value, error) {
return nil, err
})
}
}
// Reject returns a hook that rejects all operations that match op.
//
// func (T) Hooks() []ent.Hook {
// return []ent.Hook{
// Reject(ent.Delete|ent.Update),
// }
// }
func Reject(op ent.Op) ent.Hook {
hk := FixedError(fmt.Errorf("%s operation is not allowed", op))
return On(hk, op)
}
// Chain acts as a list of hooks and is effectively immutable.
// Once created, it will always hold the same set of hooks in the same order.
type Chain struct {
hooks []ent.Hook
}
// NewChain creates a new chain of hooks.
func NewChain(hooks ...ent.Hook) Chain {
return Chain{append([]ent.Hook(nil), hooks...)}
}
// Hook chains the list of hooks and returns the final hook.
func (c Chain) Hook() ent.Hook {
return func(mutator ent.Mutator) ent.Mutator {
for i := len(c.hooks) - 1; i >= 0; i-- {
mutator = c.hooks[i](mutator)
}
return mutator
}
}
// Append extends a chain, adding the specified hook
// as the last ones in the mutation flow.
func (c Chain) Append(hooks ...ent.Hook) Chain {
newHooks := make([]ent.Hook, 0, len(c.hooks)+len(hooks))
newHooks = append(newHooks, c.hooks...)
newHooks = append(newHooks, hooks...)
return Chain{newHooks}
}
// Extend extends a chain, adding the specified chain
// as the last ones in the mutation flow.
func (c Chain) Extend(chain Chain) Chain {
return c.Append(chain.hooks...)
}
================================================
FILE: cmd/atlas/internal/migrate/ent/internal/schemaconfig.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package internal
import "context"
// SchemaConfig represents alternative schema names for all tables
// that can be passed at runtime.
type SchemaConfig struct {
Revision string // Revision table.
}
type schemaCtxKey struct{}
// SchemaConfigFromContext returns a SchemaConfig stored inside a context, or empty if there isn't one.
func SchemaConfigFromContext(ctx context.Context) SchemaConfig {
config, _ := ctx.Value(schemaCtxKey{}).(SchemaConfig)
return config
}
// NewSchemaConfigContext returns a new context with the given SchemaConfig attached.
func NewSchemaConfigContext(parent context.Context, config SchemaConfig) context.Context {
return context.WithValue(parent, schemaCtxKey{}, config)
}
================================================
FILE: cmd/atlas/internal/migrate/ent/migrate/migrate.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package migrate
import (
"context"
"fmt"
"io"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql/schema"
)
var (
// WithGlobalUniqueID sets the universal ids options to the migration.
// If this option is enabled, ent migration will allocate a 1<<32 range
// for the ids of each entity (table).
// Note that this option cannot be applied on tables that already exist.
WithGlobalUniqueID = schema.WithGlobalUniqueID
// WithDropColumn sets the drop column option to the migration.
// If this option is enabled, ent migration will drop old columns
// that were used for both fields and edges. This defaults to false.
WithDropColumn = schema.WithDropColumn
// WithDropIndex sets the drop index option to the migration.
// If this option is enabled, ent migration will drop old indexes
// that were defined in the schema. This defaults to false.
// Note that unique constraints are defined using `UNIQUE INDEX`,
// and therefore, it's recommended to enable this option to get more
// flexibility in the schema changes.
WithDropIndex = schema.WithDropIndex
// WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true.
WithForeignKeys = schema.WithForeignKeys
)
// Schema is the API for creating, migrating and dropping a schema.
type Schema struct {
drv dialect.Driver
}
// NewSchema creates a new schema client.
func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} }
// Create creates all schema resources.
func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error {
return Create(ctx, s, Tables, opts...)
}
// Create creates all table resources using the given schema driver.
func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error {
migrate, err := schema.NewMigrate(s.drv, opts...)
if err != nil {
return fmt.Errorf("ent/migrate: %w", err)
}
return migrate.Create(ctx, tables...)
}
// WriteTo writes the schema changes to w instead of running them against the database.
//
// if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil {
// log.Fatal(err)
// }
func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error {
return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...)
}
================================================
FILE: cmd/atlas/internal/migrate/ent/migrate/schema.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package migrate
import (
"entgo.io/ent/dialect/entsql"
"entgo.io/ent/dialect/sql/schema"
"entgo.io/ent/schema/field"
)
var (
// AtlasSchemaRevisionsColumns holds the columns for the "atlas_schema_revisions" table.
AtlasSchemaRevisionsColumns = []*schema.Column{
{Name: "version", Type: field.TypeString},
{Name: "description", Type: field.TypeString},
{Name: "type", Type: field.TypeUint, Default: 2},
{Name: "applied", Type: field.TypeInt, Default: 0},
{Name: "total", Type: field.TypeInt, Default: 0},
{Name: "executed_at", Type: field.TypeTime},
{Name: "execution_time", Type: field.TypeInt64},
{Name: "error", Type: field.TypeString, Nullable: true, Size: 2147483647},
{Name: "error_stmt", Type: field.TypeString, Nullable: true, Size: 2147483647},
{Name: "hash", Type: field.TypeString},
{Name: "partial_hashes", Type: field.TypeJSON, Nullable: true},
{Name: "operator_version", Type: field.TypeString},
}
// AtlasSchemaRevisionsTable holds the schema information for the "atlas_schema_revisions" table.
AtlasSchemaRevisionsTable = &schema.Table{
Name: "atlas_schema_revisions",
Columns: AtlasSchemaRevisionsColumns,
PrimaryKey: []*schema.Column{AtlasSchemaRevisionsColumns[0]},
}
// Tables holds all the tables in the schema.
Tables = []*schema.Table{
AtlasSchemaRevisionsTable,
}
)
func init() {
AtlasSchemaRevisionsTable.Annotation = &entsql.Annotation{
Table: "atlas_schema_revisions",
}
}
================================================
FILE: cmd/atlas/internal/migrate/ent/mutation.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package ent
import (
"context"
"errors"
"fmt"
"sync"
"time"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/predicate"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"ariga.io/atlas/sql/migrate"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
)
const (
// Operation types.
OpCreate = ent.OpCreate
OpDelete = ent.OpDelete
OpDeleteOne = ent.OpDeleteOne
OpUpdate = ent.OpUpdate
OpUpdateOne = ent.OpUpdateOne
// Node types.
TypeRevision = "Revision"
)
// RevisionMutation represents an operation that mutates the Revision nodes in the graph.
type RevisionMutation struct {
config
op Op
typ string
id *string
description *string
_type *migrate.RevisionType
add_type *migrate.RevisionType
applied *int
addapplied *int
total *int
addtotal *int
executed_at *time.Time
execution_time *time.Duration
addexecution_time *time.Duration
error *string
error_stmt *string
hash *string
partial_hashes *[]string
appendpartial_hashes []string
operator_version *string
clearedFields map[string]struct{}
done bool
oldValue func(context.Context) (*Revision, error)
predicates []predicate.Revision
}
var _ ent.Mutation = (*RevisionMutation)(nil)
// revisionOption allows management of the mutation configuration using functional options.
type revisionOption func(*RevisionMutation)
// newRevisionMutation creates new mutation for the Revision entity.
func newRevisionMutation(c config, op Op, opts ...revisionOption) *RevisionMutation {
m := &RevisionMutation{
config: c,
op: op,
typ: TypeRevision,
clearedFields: make(map[string]struct{}),
}
for _, opt := range opts {
opt(m)
}
return m
}
// withRevisionID sets the ID field of the mutation.
func withRevisionID(id string) revisionOption {
return func(m *RevisionMutation) {
var (
err error
once sync.Once
value *Revision
)
m.oldValue = func(ctx context.Context) (*Revision, error) {
once.Do(func() {
if m.done {
err = errors.New("querying old values post mutation is not allowed")
} else {
value, err = m.Client().Revision.Get(ctx, id)
}
})
return value, err
}
m.id = &id
}
}
// withRevision sets the old Revision of the mutation.
func withRevision(node *Revision) revisionOption {
return func(m *RevisionMutation) {
m.oldValue = func(context.Context) (*Revision, error) {
return node, nil
}
m.id = &node.ID
}
}
// Client returns a new `ent.Client` from the mutation. If the mutation was
// executed in a transaction (ent.Tx), a transactional client is returned.
func (m RevisionMutation) Client() *Client {
client := &Client{config: m.config}
client.init()
return client
}
// Tx returns an `ent.Tx` for mutations that were executed in transactions;
// it returns an error otherwise.
func (m RevisionMutation) Tx() (*Tx, error) {
if _, ok := m.driver.(*txDriver); !ok {
return nil, errors.New("ent: mutation is not running in a transaction")
}
tx := &Tx{config: m.config}
tx.init()
return tx, nil
}
// SetID sets the value of the id field. Note that this
// operation is only accepted on creation of Revision entities.
func (m *RevisionMutation) SetID(id string) {
m.id = &id
}
// ID returns the ID value in the mutation. Note that the ID is only available
// if it was provided to the builder or after it was returned from the database.
func (m *RevisionMutation) ID() (id string, exists bool) {
if m.id == nil {
return
}
return *m.id, true
}
// IDs queries the database and returns the entity ids that match the mutation's predicate.
// That means, if the mutation is applied within a transaction with an isolation level such
// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated
// or updated by the mutation.
func (m *RevisionMutation) IDs(ctx context.Context) ([]string, error) {
switch {
case m.op.Is(OpUpdateOne | OpDeleteOne):
id, exists := m.ID()
if exists {
return []string{id}, nil
}
fallthrough
case m.op.Is(OpUpdate | OpDelete):
return m.Client().Revision.Query().Where(m.predicates...).IDs(ctx)
default:
return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op)
}
}
// SetDescription sets the "description" field.
func (m *RevisionMutation) SetDescription(s string) {
m.description = &s
}
// Description returns the value of the "description" field in the mutation.
func (m *RevisionMutation) Description() (r string, exists bool) {
v := m.description
if v == nil {
return
}
return *v, true
}
// OldDescription returns the old "description" field's value of the Revision entity.
// If the Revision object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *RevisionMutation) OldDescription(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldDescription is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldDescription requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldDescription: %w", err)
}
return oldValue.Description, nil
}
// ResetDescription resets all changes to the "description" field.
func (m *RevisionMutation) ResetDescription() {
m.description = nil
}
// SetType sets the "type" field.
func (m *RevisionMutation) SetType(mt migrate.RevisionType) {
m._type = &mt
m.add_type = nil
}
// GetType returns the value of the "type" field in the mutation.
func (m *RevisionMutation) GetType() (r migrate.RevisionType, exists bool) {
v := m._type
if v == nil {
return
}
return *v, true
}
// OldType returns the old "type" field's value of the Revision entity.
// If the Revision object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *RevisionMutation) OldType(ctx context.Context) (v migrate.RevisionType, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldType is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldType requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldType: %w", err)
}
return oldValue.Type, nil
}
// AddType adds mt to the "type" field.
func (m *RevisionMutation) AddType(mt migrate.RevisionType) {
if m.add_type != nil {
*m.add_type += mt
} else {
m.add_type = &mt
}
}
// AddedType returns the value that was added to the "type" field in this mutation.
func (m *RevisionMutation) AddedType() (r migrate.RevisionType, exists bool) {
v := m.add_type
if v == nil {
return
}
return *v, true
}
// ResetType resets all changes to the "type" field.
func (m *RevisionMutation) ResetType() {
m._type = nil
m.add_type = nil
}
// SetApplied sets the "applied" field.
func (m *RevisionMutation) SetApplied(i int) {
m.applied = &i
m.addapplied = nil
}
// Applied returns the value of the "applied" field in the mutation.
func (m *RevisionMutation) Applied() (r int, exists bool) {
v := m.applied
if v == nil {
return
}
return *v, true
}
// OldApplied returns the old "applied" field's value of the Revision entity.
// If the Revision object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *RevisionMutation) OldApplied(ctx context.Context) (v int, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldApplied is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldApplied requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldApplied: %w", err)
}
return oldValue.Applied, nil
}
// AddApplied adds i to the "applied" field.
func (m *RevisionMutation) AddApplied(i int) {
if m.addapplied != nil {
*m.addapplied += i
} else {
m.addapplied = &i
}
}
// AddedApplied returns the value that was added to the "applied" field in this mutation.
func (m *RevisionMutation) AddedApplied() (r int, exists bool) {
v := m.addapplied
if v == nil {
return
}
return *v, true
}
// ResetApplied resets all changes to the "applied" field.
func (m *RevisionMutation) ResetApplied() {
m.applied = nil
m.addapplied = nil
}
// SetTotal sets the "total" field.
func (m *RevisionMutation) SetTotal(i int) {
m.total = &i
m.addtotal = nil
}
// Total returns the value of the "total" field in the mutation.
func (m *RevisionMutation) Total() (r int, exists bool) {
v := m.total
if v == nil {
return
}
return *v, true
}
// OldTotal returns the old "total" field's value of the Revision entity.
// If the Revision object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *RevisionMutation) OldTotal(ctx context.Context) (v int, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldTotal is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldTotal requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldTotal: %w", err)
}
return oldValue.Total, nil
}
// AddTotal adds i to the "total" field.
func (m *RevisionMutation) AddTotal(i int) {
if m.addtotal != nil {
*m.addtotal += i
} else {
m.addtotal = &i
}
}
// AddedTotal returns the value that was added to the "total" field in this mutation.
func (m *RevisionMutation) AddedTotal() (r int, exists bool) {
v := m.addtotal
if v == nil {
return
}
return *v, true
}
// ResetTotal resets all changes to the "total" field.
func (m *RevisionMutation) ResetTotal() {
m.total = nil
m.addtotal = nil
}
// SetExecutedAt sets the "executed_at" field.
func (m *RevisionMutation) SetExecutedAt(t time.Time) {
m.executed_at = &t
}
// ExecutedAt returns the value of the "executed_at" field in the mutation.
func (m *RevisionMutation) ExecutedAt() (r time.Time, exists bool) {
v := m.executed_at
if v == nil {
return
}
return *v, true
}
// OldExecutedAt returns the old "executed_at" field's value of the Revision entity.
// If the Revision object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *RevisionMutation) OldExecutedAt(ctx context.Context) (v time.Time, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldExecutedAt is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldExecutedAt requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldExecutedAt: %w", err)
}
return oldValue.ExecutedAt, nil
}
// ResetExecutedAt resets all changes to the "executed_at" field.
func (m *RevisionMutation) ResetExecutedAt() {
m.executed_at = nil
}
// SetExecutionTime sets the "execution_time" field.
func (m *RevisionMutation) SetExecutionTime(t time.Duration) {
m.execution_time = &t
m.addexecution_time = nil
}
// ExecutionTime returns the value of the "execution_time" field in the mutation.
func (m *RevisionMutation) ExecutionTime() (r time.Duration, exists bool) {
v := m.execution_time
if v == nil {
return
}
return *v, true
}
// OldExecutionTime returns the old "execution_time" field's value of the Revision entity.
// If the Revision object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *RevisionMutation) OldExecutionTime(ctx context.Context) (v time.Duration, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldExecutionTime is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldExecutionTime requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldExecutionTime: %w", err)
}
return oldValue.ExecutionTime, nil
}
// AddExecutionTime adds t to the "execution_time" field.
func (m *RevisionMutation) AddExecutionTime(t time.Duration) {
if m.addexecution_time != nil {
*m.addexecution_time += t
} else {
m.addexecution_time = &t
}
}
// AddedExecutionTime returns the value that was added to the "execution_time" field in this mutation.
func (m *RevisionMutation) AddedExecutionTime() (r time.Duration, exists bool) {
v := m.addexecution_time
if v == nil {
return
}
return *v, true
}
// ResetExecutionTime resets all changes to the "execution_time" field.
func (m *RevisionMutation) ResetExecutionTime() {
m.execution_time = nil
m.addexecution_time = nil
}
// SetError sets the "error" field.
func (m *RevisionMutation) SetError(s string) {
m.error = &s
}
// Error returns the value of the "error" field in the mutation.
func (m *RevisionMutation) Error() (r string, exists bool) {
v := m.error
if v == nil {
return
}
return *v, true
}
// OldError returns the old "error" field's value of the Revision entity.
// If the Revision object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *RevisionMutation) OldError(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldError is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldError requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldError: %w", err)
}
return oldValue.Error, nil
}
// ClearError clears the value of the "error" field.
func (m *RevisionMutation) ClearError() {
m.error = nil
m.clearedFields[revision.FieldError] = struct{}{}
}
// ErrorCleared returns if the "error" field was cleared in this mutation.
func (m *RevisionMutation) ErrorCleared() bool {
_, ok := m.clearedFields[revision.FieldError]
return ok
}
// ResetError resets all changes to the "error" field.
func (m *RevisionMutation) ResetError() {
m.error = nil
delete(m.clearedFields, revision.FieldError)
}
// SetErrorStmt sets the "error_stmt" field.
func (m *RevisionMutation) SetErrorStmt(s string) {
m.error_stmt = &s
}
// ErrorStmt returns the value of the "error_stmt" field in the mutation.
func (m *RevisionMutation) ErrorStmt() (r string, exists bool) {
v := m.error_stmt
if v == nil {
return
}
return *v, true
}
// OldErrorStmt returns the old "error_stmt" field's value of the Revision entity.
// If the Revision object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *RevisionMutation) OldErrorStmt(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldErrorStmt is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldErrorStmt requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldErrorStmt: %w", err)
}
return oldValue.ErrorStmt, nil
}
// ClearErrorStmt clears the value of the "error_stmt" field.
func (m *RevisionMutation) ClearErrorStmt() {
m.error_stmt = nil
m.clearedFields[revision.FieldErrorStmt] = struct{}{}
}
// ErrorStmtCleared returns if the "error_stmt" field was cleared in this mutation.
func (m *RevisionMutation) ErrorStmtCleared() bool {
_, ok := m.clearedFields[revision.FieldErrorStmt]
return ok
}
// ResetErrorStmt resets all changes to the "error_stmt" field.
func (m *RevisionMutation) ResetErrorStmt() {
m.error_stmt = nil
delete(m.clearedFields, revision.FieldErrorStmt)
}
// SetHash sets the "hash" field.
func (m *RevisionMutation) SetHash(s string) {
m.hash = &s
}
// Hash returns the value of the "hash" field in the mutation.
func (m *RevisionMutation) Hash() (r string, exists bool) {
v := m.hash
if v == nil {
return
}
return *v, true
}
// OldHash returns the old "hash" field's value of the Revision entity.
// If the Revision object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *RevisionMutation) OldHash(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldHash is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldHash requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldHash: %w", err)
}
return oldValue.Hash, nil
}
// ResetHash resets all changes to the "hash" field.
func (m *RevisionMutation) ResetHash() {
m.hash = nil
}
// SetPartialHashes sets the "partial_hashes" field.
func (m *RevisionMutation) SetPartialHashes(s []string) {
m.partial_hashes = &s
m.appendpartial_hashes = nil
}
// PartialHashes returns the value of the "partial_hashes" field in the mutation.
func (m *RevisionMutation) PartialHashes() (r []string, exists bool) {
v := m.partial_hashes
if v == nil {
return
}
return *v, true
}
// OldPartialHashes returns the old "partial_hashes" field's value of the Revision entity.
// If the Revision object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *RevisionMutation) OldPartialHashes(ctx context.Context) (v []string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldPartialHashes is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldPartialHashes requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldPartialHashes: %w", err)
}
return oldValue.PartialHashes, nil
}
// AppendPartialHashes adds s to the "partial_hashes" field.
func (m *RevisionMutation) AppendPartialHashes(s []string) {
m.appendpartial_hashes = append(m.appendpartial_hashes, s...)
}
// AppendedPartialHashes returns the list of values that were appended to the "partial_hashes" field in this mutation.
func (m *RevisionMutation) AppendedPartialHashes() ([]string, bool) {
if len(m.appendpartial_hashes) == 0 {
return nil, false
}
return m.appendpartial_hashes, true
}
// ClearPartialHashes clears the value of the "partial_hashes" field.
func (m *RevisionMutation) ClearPartialHashes() {
m.partial_hashes = nil
m.appendpartial_hashes = nil
m.clearedFields[revision.FieldPartialHashes] = struct{}{}
}
// PartialHashesCleared returns if the "partial_hashes" field was cleared in this mutation.
func (m *RevisionMutation) PartialHashesCleared() bool {
_, ok := m.clearedFields[revision.FieldPartialHashes]
return ok
}
// ResetPartialHashes resets all changes to the "partial_hashes" field.
func (m *RevisionMutation) ResetPartialHashes() {
m.partial_hashes = nil
m.appendpartial_hashes = nil
delete(m.clearedFields, revision.FieldPartialHashes)
}
// SetOperatorVersion sets the "operator_version" field.
func (m *RevisionMutation) SetOperatorVersion(s string) {
m.operator_version = &s
}
// OperatorVersion returns the value of the "operator_version" field in the mutation.
func (m *RevisionMutation) OperatorVersion() (r string, exists bool) {
v := m.operator_version
if v == nil {
return
}
return *v, true
}
// OldOperatorVersion returns the old "operator_version" field's value of the Revision entity.
// If the Revision object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *RevisionMutation) OldOperatorVersion(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldOperatorVersion is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldOperatorVersion requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldOperatorVersion: %w", err)
}
return oldValue.OperatorVersion, nil
}
// ResetOperatorVersion resets all changes to the "operator_version" field.
func (m *RevisionMutation) ResetOperatorVersion() {
m.operator_version = nil
}
// Where appends a list predicates to the RevisionMutation builder.
func (m *RevisionMutation) Where(ps ...predicate.Revision) {
m.predicates = append(m.predicates, ps...)
}
// WhereP appends storage-level predicates to the RevisionMutation builder. Using this method,
// users can use type-assertion to append predicates that do not depend on any generated package.
func (m *RevisionMutation) WhereP(ps ...func(*sql.Selector)) {
p := make([]predicate.Revision, len(ps))
for i := range ps {
p[i] = ps[i]
}
m.Where(p...)
}
// Op returns the operation name.
func (m *RevisionMutation) Op() Op {
return m.op
}
// SetOp allows setting the mutation operation.
func (m *RevisionMutation) SetOp(op Op) {
m.op = op
}
// Type returns the node type of this mutation (Revision).
func (m *RevisionMutation) Type() string {
return m.typ
}
// Fields returns all fields that were changed during this mutation. Note that in
// order to get all numeric fields that were incremented/decremented, call
// AddedFields().
func (m *RevisionMutation) Fields() []string {
fields := make([]string, 0, 11)
if m.description != nil {
fields = append(fields, revision.FieldDescription)
}
if m._type != nil {
fields = append(fields, revision.FieldType)
}
if m.applied != nil {
fields = append(fields, revision.FieldApplied)
}
if m.total != nil {
fields = append(fields, revision.FieldTotal)
}
if m.executed_at != nil {
fields = append(fields, revision.FieldExecutedAt)
}
if m.execution_time != nil {
fields = append(fields, revision.FieldExecutionTime)
}
if m.error != nil {
fields = append(fields, revision.FieldError)
}
if m.error_stmt != nil {
fields = append(fields, revision.FieldErrorStmt)
}
if m.hash != nil {
fields = append(fields, revision.FieldHash)
}
if m.partial_hashes != nil {
fields = append(fields, revision.FieldPartialHashes)
}
if m.operator_version != nil {
fields = append(fields, revision.FieldOperatorVersion)
}
return fields
}
// Field returns the value of a field with the given name. The second boolean
// return value indicates that this field was not set, or was not defined in the
// schema.
func (m *RevisionMutation) Field(name string) (ent.Value, bool) {
switch name {
case revision.FieldDescription:
return m.Description()
case revision.FieldType:
return m.GetType()
case revision.FieldApplied:
return m.Applied()
case revision.FieldTotal:
return m.Total()
case revision.FieldExecutedAt:
return m.ExecutedAt()
case revision.FieldExecutionTime:
return m.ExecutionTime()
case revision.FieldError:
return m.Error()
case revision.FieldErrorStmt:
return m.ErrorStmt()
case revision.FieldHash:
return m.Hash()
case revision.FieldPartialHashes:
return m.PartialHashes()
case revision.FieldOperatorVersion:
return m.OperatorVersion()
}
return nil, false
}
// OldField returns the old value of the field from the database. An error is
// returned if the mutation operation is not UpdateOne, or the query to the
// database failed.
func (m *RevisionMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
switch name {
case revision.FieldDescription:
return m.OldDescription(ctx)
case revision.FieldType:
return m.OldType(ctx)
case revision.FieldApplied:
return m.OldApplied(ctx)
case revision.FieldTotal:
return m.OldTotal(ctx)
case revision.FieldExecutedAt:
return m.OldExecutedAt(ctx)
case revision.FieldExecutionTime:
return m.OldExecutionTime(ctx)
case revision.FieldError:
return m.OldError(ctx)
case revision.FieldErrorStmt:
return m.OldErrorStmt(ctx)
case revision.FieldHash:
return m.OldHash(ctx)
case revision.FieldPartialHashes:
return m.OldPartialHashes(ctx)
case revision.FieldOperatorVersion:
return m.OldOperatorVersion(ctx)
}
return nil, fmt.Errorf("unknown Revision field %s", name)
}
// SetField sets the value of a field with the given name. It returns an error if
// the field is not defined in the schema, or if the type mismatched the field
// type.
func (m *RevisionMutation) SetField(name string, value ent.Value) error {
switch name {
case revision.FieldDescription:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetDescription(v)
return nil
case revision.FieldType:
v, ok := value.(migrate.RevisionType)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetType(v)
return nil
case revision.FieldApplied:
v, ok := value.(int)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetApplied(v)
return nil
case revision.FieldTotal:
v, ok := value.(int)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetTotal(v)
return nil
case revision.FieldExecutedAt:
v, ok := value.(time.Time)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetExecutedAt(v)
return nil
case revision.FieldExecutionTime:
v, ok := value.(time.Duration)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetExecutionTime(v)
return nil
case revision.FieldError:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetError(v)
return nil
case revision.FieldErrorStmt:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetErrorStmt(v)
return nil
case revision.FieldHash:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetHash(v)
return nil
case revision.FieldPartialHashes:
v, ok := value.([]string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetPartialHashes(v)
return nil
case revision.FieldOperatorVersion:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetOperatorVersion(v)
return nil
}
return fmt.Errorf("unknown Revision field %s", name)
}
// AddedFields returns all numeric fields that were incremented/decremented during
// this mutation.
func (m *RevisionMutation) AddedFields() []string {
var fields []string
if m.add_type != nil {
fields = append(fields, revision.FieldType)
}
if m.addapplied != nil {
fields = append(fields, revision.FieldApplied)
}
if m.addtotal != nil {
fields = append(fields, revision.FieldTotal)
}
if m.addexecution_time != nil {
fields = append(fields, revision.FieldExecutionTime)
}
return fields
}
// AddedField returns the numeric value that was incremented/decremented on a field
// with the given name. The second boolean return value indicates that this field
// was not set, or was not defined in the schema.
func (m *RevisionMutation) AddedField(name string) (ent.Value, bool) {
switch name {
case revision.FieldType:
return m.AddedType()
case revision.FieldApplied:
return m.AddedApplied()
case revision.FieldTotal:
return m.AddedTotal()
case revision.FieldExecutionTime:
return m.AddedExecutionTime()
}
return nil, false
}
// AddField adds the value to the field with the given name. It returns an error if
// the field is not defined in the schema, or if the type mismatched the field
// type.
func (m *RevisionMutation) AddField(name string, value ent.Value) error {
switch name {
case revision.FieldType:
v, ok := value.(migrate.RevisionType)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.AddType(v)
return nil
case revision.FieldApplied:
v, ok := value.(int)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.AddApplied(v)
return nil
case revision.FieldTotal:
v, ok := value.(int)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.AddTotal(v)
return nil
case revision.FieldExecutionTime:
v, ok := value.(time.Duration)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.AddExecutionTime(v)
return nil
}
return fmt.Errorf("unknown Revision numeric field %s", name)
}
// ClearedFields returns all nullable fields that were cleared during this
// mutation.
func (m *RevisionMutation) ClearedFields() []string {
var fields []string
if m.FieldCleared(revision.FieldError) {
fields = append(fields, revision.FieldError)
}
if m.FieldCleared(revision.FieldErrorStmt) {
fields = append(fields, revision.FieldErrorStmt)
}
if m.FieldCleared(revision.FieldPartialHashes) {
fields = append(fields, revision.FieldPartialHashes)
}
return fields
}
// FieldCleared returns a boolean indicating if a field with the given name was
// cleared in this mutation.
func (m *RevisionMutation) FieldCleared(name string) bool {
_, ok := m.clearedFields[name]
return ok
}
// ClearField clears the value of the field with the given name. It returns an
// error if the field is not defined in the schema.
func (m *RevisionMutation) ClearField(name string) error {
switch name {
case revision.FieldError:
m.ClearError()
return nil
case revision.FieldErrorStmt:
m.ClearErrorStmt()
return nil
case revision.FieldPartialHashes:
m.ClearPartialHashes()
return nil
}
return fmt.Errorf("unknown Revision nullable field %s", name)
}
// ResetField resets all changes in the mutation for the field with the given name.
// It returns an error if the field is not defined in the schema.
func (m *RevisionMutation) ResetField(name string) error {
switch name {
case revision.FieldDescription:
m.ResetDescription()
return nil
case revision.FieldType:
m.ResetType()
return nil
case revision.FieldApplied:
m.ResetApplied()
return nil
case revision.FieldTotal:
m.ResetTotal()
return nil
case revision.FieldExecutedAt:
m.ResetExecutedAt()
return nil
case revision.FieldExecutionTime:
m.ResetExecutionTime()
return nil
case revision.FieldError:
m.ResetError()
return nil
case revision.FieldErrorStmt:
m.ResetErrorStmt()
return nil
case revision.FieldHash:
m.ResetHash()
return nil
case revision.FieldPartialHashes:
m.ResetPartialHashes()
return nil
case revision.FieldOperatorVersion:
m.ResetOperatorVersion()
return nil
}
return fmt.Errorf("unknown Revision field %s", name)
}
// AddedEdges returns all edge names that were set/added in this mutation.
func (m *RevisionMutation) AddedEdges() []string {
edges := make([]string, 0, 0)
return edges
}
// AddedIDs returns all IDs (to other nodes) that were added for the given edge
// name in this mutation.
func (m *RevisionMutation) AddedIDs(name string) []ent.Value {
return nil
}
// RemovedEdges returns all edge names that were removed in this mutation.
func (m *RevisionMutation) RemovedEdges() []string {
edges := make([]string, 0, 0)
return edges
}
// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
// the given name in this mutation.
func (m *RevisionMutation) RemovedIDs(name string) []ent.Value {
return nil
}
// ClearedEdges returns all edge names that were cleared in this mutation.
func (m *RevisionMutation) ClearedEdges() []string {
edges := make([]string, 0, 0)
return edges
}
// EdgeCleared returns a boolean which indicates if the edge with the given name
// was cleared in this mutation.
func (m *RevisionMutation) EdgeCleared(name string) bool {
return false
}
// ClearEdge clears the value of the edge with the given name. It returns an error
// if that edge is not defined in the schema.
func (m *RevisionMutation) ClearEdge(name string) error {
return fmt.Errorf("unknown Revision unique edge %s", name)
}
// ResetEdge resets all changes to the edge with the given name in this mutation.
// It returns an error if the edge is not defined in the schema.
func (m *RevisionMutation) ResetEdge(name string) error {
return fmt.Errorf("unknown Revision edge %s", name)
}
================================================
FILE: cmd/atlas/internal/migrate/ent/predicate/predicate.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package predicate
import (
"entgo.io/ent/dialect/sql"
)
// Revision is the predicate function for revision builders.
type Revision func(*sql.Selector)
================================================
FILE: cmd/atlas/internal/migrate/ent/revision/revision.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package revision
import (
"ariga.io/atlas/sql/migrate"
"entgo.io/ent/dialect/sql"
)
const (
// Label holds the string label denoting the revision type in the database.
Label = "revision"
// FieldID holds the string denoting the id field in the database.
FieldID = "version"
// FieldDescription holds the string denoting the description field in the database.
FieldDescription = "description"
// FieldType holds the string denoting the type field in the database.
FieldType = "type"
// FieldApplied holds the string denoting the applied field in the database.
FieldApplied = "applied"
// FieldTotal holds the string denoting the total field in the database.
FieldTotal = "total"
// FieldExecutedAt holds the string denoting the executed_at field in the database.
FieldExecutedAt = "executed_at"
// FieldExecutionTime holds the string denoting the execution_time field in the database.
FieldExecutionTime = "execution_time"
// FieldError holds the string denoting the error field in the database.
FieldError = "error"
// FieldErrorStmt holds the string denoting the error_stmt field in the database.
FieldErrorStmt = "error_stmt"
// FieldHash holds the string denoting the hash field in the database.
FieldHash = "hash"
// FieldPartialHashes holds the string denoting the partial_hashes field in the database.
FieldPartialHashes = "partial_hashes"
// FieldOperatorVersion holds the string denoting the operator_version field in the database.
FieldOperatorVersion = "operator_version"
// Table holds the table name of the revision in the database.
Table = "atlas_schema_revisions"
)
// Columns holds all SQL columns for revision fields.
var Columns = []string{
FieldID,
FieldDescription,
FieldType,
FieldApplied,
FieldTotal,
FieldExecutedAt,
FieldExecutionTime,
FieldError,
FieldErrorStmt,
FieldHash,
FieldPartialHashes,
FieldOperatorVersion,
}
// ValidColumn reports if the column name is valid (part of the table columns).
func ValidColumn(column string) bool {
for i := range Columns {
if column == Columns[i] {
return true
}
}
return false
}
var (
// DefaultType holds the default value on creation for the "type" field.
DefaultType migrate.RevisionType
// DefaultApplied holds the default value on creation for the "applied" field.
DefaultApplied int
// AppliedValidator is a validator for the "applied" field. It is called by the builders before save.
AppliedValidator func(int) error
// DefaultTotal holds the default value on creation for the "total" field.
DefaultTotal int
// TotalValidator is a validator for the "total" field. It is called by the builders before save.
TotalValidator func(int) error
)
// OrderOption defines the ordering options for the Revision queries.
type OrderOption func(*sql.Selector)
// ByID orders the results by the id field.
func ByID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldID, opts...).ToFunc()
}
// ByDescription orders the results by the description field.
func ByDescription(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDescription, opts...).ToFunc()
}
// ByType orders the results by the type field.
func ByType(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldType, opts...).ToFunc()
}
// ByApplied orders the results by the applied field.
func ByApplied(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldApplied, opts...).ToFunc()
}
// ByTotal orders the results by the total field.
func ByTotal(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldTotal, opts...).ToFunc()
}
// ByExecutedAt orders the results by the executed_at field.
func ByExecutedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldExecutedAt, opts...).ToFunc()
}
// ByExecutionTime orders the results by the execution_time field.
func ByExecutionTime(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldExecutionTime, opts...).ToFunc()
}
// ByError orders the results by the error field.
func ByError(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldError, opts...).ToFunc()
}
// ByErrorStmt orders the results by the error_stmt field.
func ByErrorStmt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldErrorStmt, opts...).ToFunc()
}
// ByHash orders the results by the hash field.
func ByHash(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldHash, opts...).ToFunc()
}
// ByOperatorVersion orders the results by the operator_version field.
func ByOperatorVersion(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldOperatorVersion, opts...).ToFunc()
}
================================================
FILE: cmd/atlas/internal/migrate/ent/revision/where.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package revision
import (
"time"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/predicate"
"ariga.io/atlas/sql/migrate"
"entgo.io/ent/dialect/sql"
)
// ID filters vertices based on their ID field.
func ID(id string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldID, id))
}
// IDEQ applies the EQ predicate on the ID field.
func IDEQ(id string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldID, id))
}
// IDNEQ applies the NEQ predicate on the ID field.
func IDNEQ(id string) predicate.Revision {
return predicate.Revision(sql.FieldNEQ(FieldID, id))
}
// IDIn applies the In predicate on the ID field.
func IDIn(ids ...string) predicate.Revision {
return predicate.Revision(sql.FieldIn(FieldID, ids...))
}
// IDNotIn applies the NotIn predicate on the ID field.
func IDNotIn(ids ...string) predicate.Revision {
return predicate.Revision(sql.FieldNotIn(FieldID, ids...))
}
// IDGT applies the GT predicate on the ID field.
func IDGT(id string) predicate.Revision {
return predicate.Revision(sql.FieldGT(FieldID, id))
}
// IDGTE applies the GTE predicate on the ID field.
func IDGTE(id string) predicate.Revision {
return predicate.Revision(sql.FieldGTE(FieldID, id))
}
// IDLT applies the LT predicate on the ID field.
func IDLT(id string) predicate.Revision {
return predicate.Revision(sql.FieldLT(FieldID, id))
}
// IDLTE applies the LTE predicate on the ID field.
func IDLTE(id string) predicate.Revision {
return predicate.Revision(sql.FieldLTE(FieldID, id))
}
// IDEqualFold applies the EqualFold predicate on the ID field.
func IDEqualFold(id string) predicate.Revision {
return predicate.Revision(sql.FieldEqualFold(FieldID, id))
}
// IDContainsFold applies the ContainsFold predicate on the ID field.
func IDContainsFold(id string) predicate.Revision {
return predicate.Revision(sql.FieldContainsFold(FieldID, id))
}
// Description applies equality check predicate on the "description" field. It's identical to DescriptionEQ.
func Description(v string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldDescription, v))
}
// Type applies equality check predicate on the "type" field. It's identical to TypeEQ.
func Type(v migrate.RevisionType) predicate.Revision {
vc := uint(v)
return predicate.Revision(sql.FieldEQ(FieldType, vc))
}
// Applied applies equality check predicate on the "applied" field. It's identical to AppliedEQ.
func Applied(v int) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldApplied, v))
}
// Total applies equality check predicate on the "total" field. It's identical to TotalEQ.
func Total(v int) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldTotal, v))
}
// ExecutedAt applies equality check predicate on the "executed_at" field. It's identical to ExecutedAtEQ.
func ExecutedAt(v time.Time) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldExecutedAt, v))
}
// ExecutionTime applies equality check predicate on the "execution_time" field. It's identical to ExecutionTimeEQ.
func ExecutionTime(v time.Duration) predicate.Revision {
vc := int64(v)
return predicate.Revision(sql.FieldEQ(FieldExecutionTime, vc))
}
// Error applies equality check predicate on the "error" field. It's identical to ErrorEQ.
func Error(v string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldError, v))
}
// ErrorStmt applies equality check predicate on the "error_stmt" field. It's identical to ErrorStmtEQ.
func ErrorStmt(v string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldErrorStmt, v))
}
// Hash applies equality check predicate on the "hash" field. It's identical to HashEQ.
func Hash(v string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldHash, v))
}
// OperatorVersion applies equality check predicate on the "operator_version" field. It's identical to OperatorVersionEQ.
func OperatorVersion(v string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldOperatorVersion, v))
}
// DescriptionEQ applies the EQ predicate on the "description" field.
func DescriptionEQ(v string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldDescription, v))
}
// DescriptionNEQ applies the NEQ predicate on the "description" field.
func DescriptionNEQ(v string) predicate.Revision {
return predicate.Revision(sql.FieldNEQ(FieldDescription, v))
}
// DescriptionIn applies the In predicate on the "description" field.
func DescriptionIn(vs ...string) predicate.Revision {
return predicate.Revision(sql.FieldIn(FieldDescription, vs...))
}
// DescriptionNotIn applies the NotIn predicate on the "description" field.
func DescriptionNotIn(vs ...string) predicate.Revision {
return predicate.Revision(sql.FieldNotIn(FieldDescription, vs...))
}
// DescriptionGT applies the GT predicate on the "description" field.
func DescriptionGT(v string) predicate.Revision {
return predicate.Revision(sql.FieldGT(FieldDescription, v))
}
// DescriptionGTE applies the GTE predicate on the "description" field.
func DescriptionGTE(v string) predicate.Revision {
return predicate.Revision(sql.FieldGTE(FieldDescription, v))
}
// DescriptionLT applies the LT predicate on the "description" field.
func DescriptionLT(v string) predicate.Revision {
return predicate.Revision(sql.FieldLT(FieldDescription, v))
}
// DescriptionLTE applies the LTE predicate on the "description" field.
func DescriptionLTE(v string) predicate.Revision {
return predicate.Revision(sql.FieldLTE(FieldDescription, v))
}
// DescriptionContains applies the Contains predicate on the "description" field.
func DescriptionContains(v string) predicate.Revision {
return predicate.Revision(sql.FieldContains(FieldDescription, v))
}
// DescriptionHasPrefix applies the HasPrefix predicate on the "description" field.
func DescriptionHasPrefix(v string) predicate.Revision {
return predicate.Revision(sql.FieldHasPrefix(FieldDescription, v))
}
// DescriptionHasSuffix applies the HasSuffix predicate on the "description" field.
func DescriptionHasSuffix(v string) predicate.Revision {
return predicate.Revision(sql.FieldHasSuffix(FieldDescription, v))
}
// DescriptionEqualFold applies the EqualFold predicate on the "description" field.
func DescriptionEqualFold(v string) predicate.Revision {
return predicate.Revision(sql.FieldEqualFold(FieldDescription, v))
}
// DescriptionContainsFold applies the ContainsFold predicate on the "description" field.
func DescriptionContainsFold(v string) predicate.Revision {
return predicate.Revision(sql.FieldContainsFold(FieldDescription, v))
}
// TypeEQ applies the EQ predicate on the "type" field.
func TypeEQ(v migrate.RevisionType) predicate.Revision {
vc := uint(v)
return predicate.Revision(sql.FieldEQ(FieldType, vc))
}
// TypeNEQ applies the NEQ predicate on the "type" field.
func TypeNEQ(v migrate.RevisionType) predicate.Revision {
vc := uint(v)
return predicate.Revision(sql.FieldNEQ(FieldType, vc))
}
// TypeIn applies the In predicate on the "type" field.
func TypeIn(vs ...migrate.RevisionType) predicate.Revision {
v := make([]any, len(vs))
for i := range v {
v[i] = uint(vs[i])
}
return predicate.Revision(sql.FieldIn(FieldType, v...))
}
// TypeNotIn applies the NotIn predicate on the "type" field.
func TypeNotIn(vs ...migrate.RevisionType) predicate.Revision {
v := make([]any, len(vs))
for i := range v {
v[i] = uint(vs[i])
}
return predicate.Revision(sql.FieldNotIn(FieldType, v...))
}
// TypeGT applies the GT predicate on the "type" field.
func TypeGT(v migrate.RevisionType) predicate.Revision {
vc := uint(v)
return predicate.Revision(sql.FieldGT(FieldType, vc))
}
// TypeGTE applies the GTE predicate on the "type" field.
func TypeGTE(v migrate.RevisionType) predicate.Revision {
vc := uint(v)
return predicate.Revision(sql.FieldGTE(FieldType, vc))
}
// TypeLT applies the LT predicate on the "type" field.
func TypeLT(v migrate.RevisionType) predicate.Revision {
vc := uint(v)
return predicate.Revision(sql.FieldLT(FieldType, vc))
}
// TypeLTE applies the LTE predicate on the "type" field.
func TypeLTE(v migrate.RevisionType) predicate.Revision {
vc := uint(v)
return predicate.Revision(sql.FieldLTE(FieldType, vc))
}
// AppliedEQ applies the EQ predicate on the "applied" field.
func AppliedEQ(v int) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldApplied, v))
}
// AppliedNEQ applies the NEQ predicate on the "applied" field.
func AppliedNEQ(v int) predicate.Revision {
return predicate.Revision(sql.FieldNEQ(FieldApplied, v))
}
// AppliedIn applies the In predicate on the "applied" field.
func AppliedIn(vs ...int) predicate.Revision {
return predicate.Revision(sql.FieldIn(FieldApplied, vs...))
}
// AppliedNotIn applies the NotIn predicate on the "applied" field.
func AppliedNotIn(vs ...int) predicate.Revision {
return predicate.Revision(sql.FieldNotIn(FieldApplied, vs...))
}
// AppliedGT applies the GT predicate on the "applied" field.
func AppliedGT(v int) predicate.Revision {
return predicate.Revision(sql.FieldGT(FieldApplied, v))
}
// AppliedGTE applies the GTE predicate on the "applied" field.
func AppliedGTE(v int) predicate.Revision {
return predicate.Revision(sql.FieldGTE(FieldApplied, v))
}
// AppliedLT applies the LT predicate on the "applied" field.
func AppliedLT(v int) predicate.Revision {
return predicate.Revision(sql.FieldLT(FieldApplied, v))
}
// AppliedLTE applies the LTE predicate on the "applied" field.
func AppliedLTE(v int) predicate.Revision {
return predicate.Revision(sql.FieldLTE(FieldApplied, v))
}
// TotalEQ applies the EQ predicate on the "total" field.
func TotalEQ(v int) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldTotal, v))
}
// TotalNEQ applies the NEQ predicate on the "total" field.
func TotalNEQ(v int) predicate.Revision {
return predicate.Revision(sql.FieldNEQ(FieldTotal, v))
}
// TotalIn applies the In predicate on the "total" field.
func TotalIn(vs ...int) predicate.Revision {
return predicate.Revision(sql.FieldIn(FieldTotal, vs...))
}
// TotalNotIn applies the NotIn predicate on the "total" field.
func TotalNotIn(vs ...int) predicate.Revision {
return predicate.Revision(sql.FieldNotIn(FieldTotal, vs...))
}
// TotalGT applies the GT predicate on the "total" field.
func TotalGT(v int) predicate.Revision {
return predicate.Revision(sql.FieldGT(FieldTotal, v))
}
// TotalGTE applies the GTE predicate on the "total" field.
func TotalGTE(v int) predicate.Revision {
return predicate.Revision(sql.FieldGTE(FieldTotal, v))
}
// TotalLT applies the LT predicate on the "total" field.
func TotalLT(v int) predicate.Revision {
return predicate.Revision(sql.FieldLT(FieldTotal, v))
}
// TotalLTE applies the LTE predicate on the "total" field.
func TotalLTE(v int) predicate.Revision {
return predicate.Revision(sql.FieldLTE(FieldTotal, v))
}
// ExecutedAtEQ applies the EQ predicate on the "executed_at" field.
func ExecutedAtEQ(v time.Time) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldExecutedAt, v))
}
// ExecutedAtNEQ applies the NEQ predicate on the "executed_at" field.
func ExecutedAtNEQ(v time.Time) predicate.Revision {
return predicate.Revision(sql.FieldNEQ(FieldExecutedAt, v))
}
// ExecutedAtIn applies the In predicate on the "executed_at" field.
func ExecutedAtIn(vs ...time.Time) predicate.Revision {
return predicate.Revision(sql.FieldIn(FieldExecutedAt, vs...))
}
// ExecutedAtNotIn applies the NotIn predicate on the "executed_at" field.
func ExecutedAtNotIn(vs ...time.Time) predicate.Revision {
return predicate.Revision(sql.FieldNotIn(FieldExecutedAt, vs...))
}
// ExecutedAtGT applies the GT predicate on the "executed_at" field.
func ExecutedAtGT(v time.Time) predicate.Revision {
return predicate.Revision(sql.FieldGT(FieldExecutedAt, v))
}
// ExecutedAtGTE applies the GTE predicate on the "executed_at" field.
func ExecutedAtGTE(v time.Time) predicate.Revision {
return predicate.Revision(sql.FieldGTE(FieldExecutedAt, v))
}
// ExecutedAtLT applies the LT predicate on the "executed_at" field.
func ExecutedAtLT(v time.Time) predicate.Revision {
return predicate.Revision(sql.FieldLT(FieldExecutedAt, v))
}
// ExecutedAtLTE applies the LTE predicate on the "executed_at" field.
func ExecutedAtLTE(v time.Time) predicate.Revision {
return predicate.Revision(sql.FieldLTE(FieldExecutedAt, v))
}
// ExecutionTimeEQ applies the EQ predicate on the "execution_time" field.
func ExecutionTimeEQ(v time.Duration) predicate.Revision {
vc := int64(v)
return predicate.Revision(sql.FieldEQ(FieldExecutionTime, vc))
}
// ExecutionTimeNEQ applies the NEQ predicate on the "execution_time" field.
func ExecutionTimeNEQ(v time.Duration) predicate.Revision {
vc := int64(v)
return predicate.Revision(sql.FieldNEQ(FieldExecutionTime, vc))
}
// ExecutionTimeIn applies the In predicate on the "execution_time" field.
func ExecutionTimeIn(vs ...time.Duration) predicate.Revision {
v := make([]any, len(vs))
for i := range v {
v[i] = int64(vs[i])
}
return predicate.Revision(sql.FieldIn(FieldExecutionTime, v...))
}
// ExecutionTimeNotIn applies the NotIn predicate on the "execution_time" field.
func ExecutionTimeNotIn(vs ...time.Duration) predicate.Revision {
v := make([]any, len(vs))
for i := range v {
v[i] = int64(vs[i])
}
return predicate.Revision(sql.FieldNotIn(FieldExecutionTime, v...))
}
// ExecutionTimeGT applies the GT predicate on the "execution_time" field.
func ExecutionTimeGT(v time.Duration) predicate.Revision {
vc := int64(v)
return predicate.Revision(sql.FieldGT(FieldExecutionTime, vc))
}
// ExecutionTimeGTE applies the GTE predicate on the "execution_time" field.
func ExecutionTimeGTE(v time.Duration) predicate.Revision {
vc := int64(v)
return predicate.Revision(sql.FieldGTE(FieldExecutionTime, vc))
}
// ExecutionTimeLT applies the LT predicate on the "execution_time" field.
func ExecutionTimeLT(v time.Duration) predicate.Revision {
vc := int64(v)
return predicate.Revision(sql.FieldLT(FieldExecutionTime, vc))
}
// ExecutionTimeLTE applies the LTE predicate on the "execution_time" field.
func ExecutionTimeLTE(v time.Duration) predicate.Revision {
vc := int64(v)
return predicate.Revision(sql.FieldLTE(FieldExecutionTime, vc))
}
// ErrorEQ applies the EQ predicate on the "error" field.
func ErrorEQ(v string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldError, v))
}
// ErrorNEQ applies the NEQ predicate on the "error" field.
func ErrorNEQ(v string) predicate.Revision {
return predicate.Revision(sql.FieldNEQ(FieldError, v))
}
// ErrorIn applies the In predicate on the "error" field.
func ErrorIn(vs ...string) predicate.Revision {
return predicate.Revision(sql.FieldIn(FieldError, vs...))
}
// ErrorNotIn applies the NotIn predicate on the "error" field.
func ErrorNotIn(vs ...string) predicate.Revision {
return predicate.Revision(sql.FieldNotIn(FieldError, vs...))
}
// ErrorGT applies the GT predicate on the "error" field.
func ErrorGT(v string) predicate.Revision {
return predicate.Revision(sql.FieldGT(FieldError, v))
}
// ErrorGTE applies the GTE predicate on the "error" field.
func ErrorGTE(v string) predicate.Revision {
return predicate.Revision(sql.FieldGTE(FieldError, v))
}
// ErrorLT applies the LT predicate on the "error" field.
func ErrorLT(v string) predicate.Revision {
return predicate.Revision(sql.FieldLT(FieldError, v))
}
// ErrorLTE applies the LTE predicate on the "error" field.
func ErrorLTE(v string) predicate.Revision {
return predicate.Revision(sql.FieldLTE(FieldError, v))
}
// ErrorContains applies the Contains predicate on the "error" field.
func ErrorContains(v string) predicate.Revision {
return predicate.Revision(sql.FieldContains(FieldError, v))
}
// ErrorHasPrefix applies the HasPrefix predicate on the "error" field.
func ErrorHasPrefix(v string) predicate.Revision {
return predicate.Revision(sql.FieldHasPrefix(FieldError, v))
}
// ErrorHasSuffix applies the HasSuffix predicate on the "error" field.
func ErrorHasSuffix(v string) predicate.Revision {
return predicate.Revision(sql.FieldHasSuffix(FieldError, v))
}
// ErrorIsNil applies the IsNil predicate on the "error" field.
func ErrorIsNil() predicate.Revision {
return predicate.Revision(sql.FieldIsNull(FieldError))
}
// ErrorNotNil applies the NotNil predicate on the "error" field.
func ErrorNotNil() predicate.Revision {
return predicate.Revision(sql.FieldNotNull(FieldError))
}
// ErrorEqualFold applies the EqualFold predicate on the "error" field.
func ErrorEqualFold(v string) predicate.Revision {
return predicate.Revision(sql.FieldEqualFold(FieldError, v))
}
// ErrorContainsFold applies the ContainsFold predicate on the "error" field.
func ErrorContainsFold(v string) predicate.Revision {
return predicate.Revision(sql.FieldContainsFold(FieldError, v))
}
// ErrorStmtEQ applies the EQ predicate on the "error_stmt" field.
func ErrorStmtEQ(v string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldErrorStmt, v))
}
// ErrorStmtNEQ applies the NEQ predicate on the "error_stmt" field.
func ErrorStmtNEQ(v string) predicate.Revision {
return predicate.Revision(sql.FieldNEQ(FieldErrorStmt, v))
}
// ErrorStmtIn applies the In predicate on the "error_stmt" field.
func ErrorStmtIn(vs ...string) predicate.Revision {
return predicate.Revision(sql.FieldIn(FieldErrorStmt, vs...))
}
// ErrorStmtNotIn applies the NotIn predicate on the "error_stmt" field.
func ErrorStmtNotIn(vs ...string) predicate.Revision {
return predicate.Revision(sql.FieldNotIn(FieldErrorStmt, vs...))
}
// ErrorStmtGT applies the GT predicate on the "error_stmt" field.
func ErrorStmtGT(v string) predicate.Revision {
return predicate.Revision(sql.FieldGT(FieldErrorStmt, v))
}
// ErrorStmtGTE applies the GTE predicate on the "error_stmt" field.
func ErrorStmtGTE(v string) predicate.Revision {
return predicate.Revision(sql.FieldGTE(FieldErrorStmt, v))
}
// ErrorStmtLT applies the LT predicate on the "error_stmt" field.
func ErrorStmtLT(v string) predicate.Revision {
return predicate.Revision(sql.FieldLT(FieldErrorStmt, v))
}
// ErrorStmtLTE applies the LTE predicate on the "error_stmt" field.
func ErrorStmtLTE(v string) predicate.Revision {
return predicate.Revision(sql.FieldLTE(FieldErrorStmt, v))
}
// ErrorStmtContains applies the Contains predicate on the "error_stmt" field.
func ErrorStmtContains(v string) predicate.Revision {
return predicate.Revision(sql.FieldContains(FieldErrorStmt, v))
}
// ErrorStmtHasPrefix applies the HasPrefix predicate on the "error_stmt" field.
func ErrorStmtHasPrefix(v string) predicate.Revision {
return predicate.Revision(sql.FieldHasPrefix(FieldErrorStmt, v))
}
// ErrorStmtHasSuffix applies the HasSuffix predicate on the "error_stmt" field.
func ErrorStmtHasSuffix(v string) predicate.Revision {
return predicate.Revision(sql.FieldHasSuffix(FieldErrorStmt, v))
}
// ErrorStmtIsNil applies the IsNil predicate on the "error_stmt" field.
func ErrorStmtIsNil() predicate.Revision {
return predicate.Revision(sql.FieldIsNull(FieldErrorStmt))
}
// ErrorStmtNotNil applies the NotNil predicate on the "error_stmt" field.
func ErrorStmtNotNil() predicate.Revision {
return predicate.Revision(sql.FieldNotNull(FieldErrorStmt))
}
// ErrorStmtEqualFold applies the EqualFold predicate on the "error_stmt" field.
func ErrorStmtEqualFold(v string) predicate.Revision {
return predicate.Revision(sql.FieldEqualFold(FieldErrorStmt, v))
}
// ErrorStmtContainsFold applies the ContainsFold predicate on the "error_stmt" field.
func ErrorStmtContainsFold(v string) predicate.Revision {
return predicate.Revision(sql.FieldContainsFold(FieldErrorStmt, v))
}
// HashEQ applies the EQ predicate on the "hash" field.
func HashEQ(v string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldHash, v))
}
// HashNEQ applies the NEQ predicate on the "hash" field.
func HashNEQ(v string) predicate.Revision {
return predicate.Revision(sql.FieldNEQ(FieldHash, v))
}
// HashIn applies the In predicate on the "hash" field.
func HashIn(vs ...string) predicate.Revision {
return predicate.Revision(sql.FieldIn(FieldHash, vs...))
}
// HashNotIn applies the NotIn predicate on the "hash" field.
func HashNotIn(vs ...string) predicate.Revision {
return predicate.Revision(sql.FieldNotIn(FieldHash, vs...))
}
// HashGT applies the GT predicate on the "hash" field.
func HashGT(v string) predicate.Revision {
return predicate.Revision(sql.FieldGT(FieldHash, v))
}
// HashGTE applies the GTE predicate on the "hash" field.
func HashGTE(v string) predicate.Revision {
return predicate.Revision(sql.FieldGTE(FieldHash, v))
}
// HashLT applies the LT predicate on the "hash" field.
func HashLT(v string) predicate.Revision {
return predicate.Revision(sql.FieldLT(FieldHash, v))
}
// HashLTE applies the LTE predicate on the "hash" field.
func HashLTE(v string) predicate.Revision {
return predicate.Revision(sql.FieldLTE(FieldHash, v))
}
// HashContains applies the Contains predicate on the "hash" field.
func HashContains(v string) predicate.Revision {
return predicate.Revision(sql.FieldContains(FieldHash, v))
}
// HashHasPrefix applies the HasPrefix predicate on the "hash" field.
func HashHasPrefix(v string) predicate.Revision {
return predicate.Revision(sql.FieldHasPrefix(FieldHash, v))
}
// HashHasSuffix applies the HasSuffix predicate on the "hash" field.
func HashHasSuffix(v string) predicate.Revision {
return predicate.Revision(sql.FieldHasSuffix(FieldHash, v))
}
// HashEqualFold applies the EqualFold predicate on the "hash" field.
func HashEqualFold(v string) predicate.Revision {
return predicate.Revision(sql.FieldEqualFold(FieldHash, v))
}
// HashContainsFold applies the ContainsFold predicate on the "hash" field.
func HashContainsFold(v string) predicate.Revision {
return predicate.Revision(sql.FieldContainsFold(FieldHash, v))
}
// PartialHashesIsNil applies the IsNil predicate on the "partial_hashes" field.
func PartialHashesIsNil() predicate.Revision {
return predicate.Revision(sql.FieldIsNull(FieldPartialHashes))
}
// PartialHashesNotNil applies the NotNil predicate on the "partial_hashes" field.
func PartialHashesNotNil() predicate.Revision {
return predicate.Revision(sql.FieldNotNull(FieldPartialHashes))
}
// OperatorVersionEQ applies the EQ predicate on the "operator_version" field.
func OperatorVersionEQ(v string) predicate.Revision {
return predicate.Revision(sql.FieldEQ(FieldOperatorVersion, v))
}
// OperatorVersionNEQ applies the NEQ predicate on the "operator_version" field.
func OperatorVersionNEQ(v string) predicate.Revision {
return predicate.Revision(sql.FieldNEQ(FieldOperatorVersion, v))
}
// OperatorVersionIn applies the In predicate on the "operator_version" field.
func OperatorVersionIn(vs ...string) predicate.Revision {
return predicate.Revision(sql.FieldIn(FieldOperatorVersion, vs...))
}
// OperatorVersionNotIn applies the NotIn predicate on the "operator_version" field.
func OperatorVersionNotIn(vs ...string) predicate.Revision {
return predicate.Revision(sql.FieldNotIn(FieldOperatorVersion, vs...))
}
// OperatorVersionGT applies the GT predicate on the "operator_version" field.
func OperatorVersionGT(v string) predicate.Revision {
return predicate.Revision(sql.FieldGT(FieldOperatorVersion, v))
}
// OperatorVersionGTE applies the GTE predicate on the "operator_version" field.
func OperatorVersionGTE(v string) predicate.Revision {
return predicate.Revision(sql.FieldGTE(FieldOperatorVersion, v))
}
// OperatorVersionLT applies the LT predicate on the "operator_version" field.
func OperatorVersionLT(v string) predicate.Revision {
return predicate.Revision(sql.FieldLT(FieldOperatorVersion, v))
}
// OperatorVersionLTE applies the LTE predicate on the "operator_version" field.
func OperatorVersionLTE(v string) predicate.Revision {
return predicate.Revision(sql.FieldLTE(FieldOperatorVersion, v))
}
// OperatorVersionContains applies the Contains predicate on the "operator_version" field.
func OperatorVersionContains(v string) predicate.Revision {
return predicate.Revision(sql.FieldContains(FieldOperatorVersion, v))
}
// OperatorVersionHasPrefix applies the HasPrefix predicate on the "operator_version" field.
func OperatorVersionHasPrefix(v string) predicate.Revision {
return predicate.Revision(sql.FieldHasPrefix(FieldOperatorVersion, v))
}
// OperatorVersionHasSuffix applies the HasSuffix predicate on the "operator_version" field.
func OperatorVersionHasSuffix(v string) predicate.Revision {
return predicate.Revision(sql.FieldHasSuffix(FieldOperatorVersion, v))
}
// OperatorVersionEqualFold applies the EqualFold predicate on the "operator_version" field.
func OperatorVersionEqualFold(v string) predicate.Revision {
return predicate.Revision(sql.FieldEqualFold(FieldOperatorVersion, v))
}
// OperatorVersionContainsFold applies the ContainsFold predicate on the "operator_version" field.
func OperatorVersionContainsFold(v string) predicate.Revision {
return predicate.Revision(sql.FieldContainsFold(FieldOperatorVersion, v))
}
// And groups predicates with the AND operator between them.
func And(predicates ...predicate.Revision) predicate.Revision {
return predicate.Revision(sql.AndPredicates(predicates...))
}
// Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.Revision) predicate.Revision {
return predicate.Revision(sql.OrPredicates(predicates...))
}
// Not applies the not operator on the given predicate.
func Not(p predicate.Revision) predicate.Revision {
return predicate.Revision(sql.NotPredicates(p))
}
================================================
FILE: cmd/atlas/internal/migrate/ent/revision.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package ent
import (
"encoding/json"
"fmt"
"strings"
"time"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"ariga.io/atlas/sql/migrate"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
)
// Revision is the model entity for the Revision schema.
type Revision struct {
config `json:"-"`
// ID of the ent.
ID string `json:"id,omitempty"`
// Description holds the value of the "description" field.
Description string `json:"description,omitempty"`
// Type holds the value of the "type" field.
Type migrate.RevisionType `json:"type,omitempty"`
// Applied holds the value of the "applied" field.
Applied int `json:"applied,omitempty"`
// Total holds the value of the "total" field.
Total int `json:"total,omitempty"`
// ExecutedAt holds the value of the "executed_at" field.
ExecutedAt time.Time `json:"executed_at,omitempty"`
// ExecutionTime holds the value of the "execution_time" field.
ExecutionTime time.Duration `json:"execution_time,omitempty"`
// Error holds the value of the "error" field.
Error string `json:"error,omitempty"`
// ErrorStmt holds the value of the "error_stmt" field.
ErrorStmt string `json:"error_stmt,omitempty"`
// Hash holds the value of the "hash" field.
Hash string `json:"hash,omitempty"`
// PartialHashes holds the value of the "partial_hashes" field.
PartialHashes []string `json:"partial_hashes,omitempty"`
// OperatorVersion holds the value of the "operator_version" field.
OperatorVersion string `json:"operator_version,omitempty"`
selectValues sql.SelectValues
}
// scanValues returns the types for scanning values from sql.Rows.
func (*Revision) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
for i := range columns {
switch columns[i] {
case revision.FieldPartialHashes:
values[i] = new([]byte)
case revision.FieldType, revision.FieldApplied, revision.FieldTotal, revision.FieldExecutionTime:
values[i] = new(sql.NullInt64)
case revision.FieldID, revision.FieldDescription, revision.FieldError, revision.FieldErrorStmt, revision.FieldHash, revision.FieldOperatorVersion:
values[i] = new(sql.NullString)
case revision.FieldExecutedAt:
values[i] = new(sql.NullTime)
default:
values[i] = new(sql.UnknownType)
}
}
return values, nil
}
// assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the Revision fields.
func (_m *Revision) assignValues(columns []string, values []any) error {
if m, n := len(values), len(columns); m < n {
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
}
for i := range columns {
switch columns[i] {
case revision.FieldID:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field id", values[i])
} else if value.Valid {
_m.ID = value.String
}
case revision.FieldDescription:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field description", values[i])
} else if value.Valid {
_m.Description = value.String
}
case revision.FieldType:
if value, ok := values[i].(*sql.NullInt64); !ok {
return fmt.Errorf("unexpected type %T for field type", values[i])
} else if value.Valid {
_m.Type = migrate.RevisionType(value.Int64)
}
case revision.FieldApplied:
if value, ok := values[i].(*sql.NullInt64); !ok {
return fmt.Errorf("unexpected type %T for field applied", values[i])
} else if value.Valid {
_m.Applied = int(value.Int64)
}
case revision.FieldTotal:
if value, ok := values[i].(*sql.NullInt64); !ok {
return fmt.Errorf("unexpected type %T for field total", values[i])
} else if value.Valid {
_m.Total = int(value.Int64)
}
case revision.FieldExecutedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field executed_at", values[i])
} else if value.Valid {
_m.ExecutedAt = value.Time
}
case revision.FieldExecutionTime:
if value, ok := values[i].(*sql.NullInt64); !ok {
return fmt.Errorf("unexpected type %T for field execution_time", values[i])
} else if value.Valid {
_m.ExecutionTime = time.Duration(value.Int64)
}
case revision.FieldError:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field error", values[i])
} else if value.Valid {
_m.Error = value.String
}
case revision.FieldErrorStmt:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field error_stmt", values[i])
} else if value.Valid {
_m.ErrorStmt = value.String
}
case revision.FieldHash:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field hash", values[i])
} else if value.Valid {
_m.Hash = value.String
}
case revision.FieldPartialHashes:
if value, ok := values[i].(*[]byte); !ok {
return fmt.Errorf("unexpected type %T for field partial_hashes", values[i])
} else if value != nil && len(*value) > 0 {
if err := json.Unmarshal(*value, &_m.PartialHashes); err != nil {
return fmt.Errorf("unmarshal field partial_hashes: %w", err)
}
}
case revision.FieldOperatorVersion:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field operator_version", values[i])
} else if value.Valid {
_m.OperatorVersion = value.String
}
default:
_m.selectValues.Set(columns[i], values[i])
}
}
return nil
}
// Value returns the ent.Value that was dynamically selected and assigned to the Revision.
// This includes values selected through modifiers, order, etc.
func (_m *Revision) Value(name string) (ent.Value, error) {
return _m.selectValues.Get(name)
}
// Update returns a builder for updating this Revision.
// Note that you need to call Revision.Unwrap() before calling this method if this Revision
// was returned from a transaction, and the transaction was committed or rolled back.
func (_m *Revision) Update() *RevisionUpdateOne {
return NewRevisionClient(_m.config).UpdateOne(_m)
}
// Unwrap unwraps the Revision entity that was returned from a transaction after it was closed,
// so that all future queries will be executed through the driver which created the transaction.
func (_m *Revision) Unwrap() *Revision {
_tx, ok := _m.config.driver.(*txDriver)
if !ok {
panic("ent: Revision is not a transactional entity")
}
_m.config.driver = _tx.drv
return _m
}
// String implements the fmt.Stringer.
func (_m *Revision) String() string {
var builder strings.Builder
builder.WriteString("Revision(")
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
builder.WriteString("description=")
builder.WriteString(_m.Description)
builder.WriteString(", ")
builder.WriteString("type=")
builder.WriteString(fmt.Sprintf("%v", _m.Type))
builder.WriteString(", ")
builder.WriteString("applied=")
builder.WriteString(fmt.Sprintf("%v", _m.Applied))
builder.WriteString(", ")
builder.WriteString("total=")
builder.WriteString(fmt.Sprintf("%v", _m.Total))
builder.WriteString(", ")
builder.WriteString("executed_at=")
builder.WriteString(_m.ExecutedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("execution_time=")
builder.WriteString(fmt.Sprintf("%v", _m.ExecutionTime))
builder.WriteString(", ")
builder.WriteString("error=")
builder.WriteString(_m.Error)
builder.WriteString(", ")
builder.WriteString("error_stmt=")
builder.WriteString(_m.ErrorStmt)
builder.WriteString(", ")
builder.WriteString("hash=")
builder.WriteString(_m.Hash)
builder.WriteString(", ")
builder.WriteString("partial_hashes=")
builder.WriteString(fmt.Sprintf("%v", _m.PartialHashes))
builder.WriteString(", ")
builder.WriteString("operator_version=")
builder.WriteString(_m.OperatorVersion)
builder.WriteByte(')')
return builder.String()
}
// Revisions is a parsable slice of Revision.
type Revisions []*Revision
================================================
FILE: cmd/atlas/internal/migrate/ent/revision_create.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package ent
import (
"context"
"errors"
"fmt"
"time"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"ariga.io/atlas/sql/migrate"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
)
// RevisionCreate is the builder for creating a Revision entity.
type RevisionCreate struct {
config
mutation *RevisionMutation
hooks []Hook
conflict []sql.ConflictOption
}
// SetDescription sets the "description" field.
func (_c *RevisionCreate) SetDescription(v string) *RevisionCreate {
_c.mutation.SetDescription(v)
return _c
}
// SetType sets the "type" field.
func (_c *RevisionCreate) SetType(v migrate.RevisionType) *RevisionCreate {
_c.mutation.SetType(v)
return _c
}
// SetNillableType sets the "type" field if the given value is not nil.
func (_c *RevisionCreate) SetNillableType(v *migrate.RevisionType) *RevisionCreate {
if v != nil {
_c.SetType(*v)
}
return _c
}
// SetApplied sets the "applied" field.
func (_c *RevisionCreate) SetApplied(v int) *RevisionCreate {
_c.mutation.SetApplied(v)
return _c
}
// SetNillableApplied sets the "applied" field if the given value is not nil.
func (_c *RevisionCreate) SetNillableApplied(v *int) *RevisionCreate {
if v != nil {
_c.SetApplied(*v)
}
return _c
}
// SetTotal sets the "total" field.
func (_c *RevisionCreate) SetTotal(v int) *RevisionCreate {
_c.mutation.SetTotal(v)
return _c
}
// SetNillableTotal sets the "total" field if the given value is not nil.
func (_c *RevisionCreate) SetNillableTotal(v *int) *RevisionCreate {
if v != nil {
_c.SetTotal(*v)
}
return _c
}
// SetExecutedAt sets the "executed_at" field.
func (_c *RevisionCreate) SetExecutedAt(v time.Time) *RevisionCreate {
_c.mutation.SetExecutedAt(v)
return _c
}
// SetExecutionTime sets the "execution_time" field.
func (_c *RevisionCreate) SetExecutionTime(v time.Duration) *RevisionCreate {
_c.mutation.SetExecutionTime(v)
return _c
}
// SetError sets the "error" field.
func (_c *RevisionCreate) SetError(v string) *RevisionCreate {
_c.mutation.SetError(v)
return _c
}
// SetNillableError sets the "error" field if the given value is not nil.
func (_c *RevisionCreate) SetNillableError(v *string) *RevisionCreate {
if v != nil {
_c.SetError(*v)
}
return _c
}
// SetErrorStmt sets the "error_stmt" field.
func (_c *RevisionCreate) SetErrorStmt(v string) *RevisionCreate {
_c.mutation.SetErrorStmt(v)
return _c
}
// SetNillableErrorStmt sets the "error_stmt" field if the given value is not nil.
func (_c *RevisionCreate) SetNillableErrorStmt(v *string) *RevisionCreate {
if v != nil {
_c.SetErrorStmt(*v)
}
return _c
}
// SetHash sets the "hash" field.
func (_c *RevisionCreate) SetHash(v string) *RevisionCreate {
_c.mutation.SetHash(v)
return _c
}
// SetPartialHashes sets the "partial_hashes" field.
func (_c *RevisionCreate) SetPartialHashes(v []string) *RevisionCreate {
_c.mutation.SetPartialHashes(v)
return _c
}
// SetOperatorVersion sets the "operator_version" field.
func (_c *RevisionCreate) SetOperatorVersion(v string) *RevisionCreate {
_c.mutation.SetOperatorVersion(v)
return _c
}
// SetID sets the "id" field.
func (_c *RevisionCreate) SetID(v string) *RevisionCreate {
_c.mutation.SetID(v)
return _c
}
// Mutation returns the RevisionMutation object of the builder.
func (_c *RevisionCreate) Mutation() *RevisionMutation {
return _c.mutation
}
// Save creates the Revision in the database.
func (_c *RevisionCreate) Save(ctx context.Context) (*Revision, error) {
_c.defaults()
return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks)
}
// SaveX calls Save and panics if Save returns an error.
func (_c *RevisionCreate) SaveX(ctx context.Context) *Revision {
v, err := _c.Save(ctx)
if err != nil {
panic(err)
}
return v
}
// Exec executes the query.
func (_c *RevisionCreate) Exec(ctx context.Context) error {
_, err := _c.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_c *RevisionCreate) ExecX(ctx context.Context) {
if err := _c.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (_c *RevisionCreate) defaults() {
if _, ok := _c.mutation.GetType(); !ok {
v := revision.DefaultType
_c.mutation.SetType(v)
}
if _, ok := _c.mutation.Applied(); !ok {
v := revision.DefaultApplied
_c.mutation.SetApplied(v)
}
if _, ok := _c.mutation.Total(); !ok {
v := revision.DefaultTotal
_c.mutation.SetTotal(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (_c *RevisionCreate) check() error {
if _, ok := _c.mutation.Description(); !ok {
return &ValidationError{Name: "description", err: errors.New(`ent: missing required field "Revision.description"`)}
}
if _, ok := _c.mutation.GetType(); !ok {
return &ValidationError{Name: "type", err: errors.New(`ent: missing required field "Revision.type"`)}
}
if _, ok := _c.mutation.Applied(); !ok {
return &ValidationError{Name: "applied", err: errors.New(`ent: missing required field "Revision.applied"`)}
}
if v, ok := _c.mutation.Applied(); ok {
if err := revision.AppliedValidator(v); err != nil {
return &ValidationError{Name: "applied", err: fmt.Errorf(`ent: validator failed for field "Revision.applied": %w`, err)}
}
}
if _, ok := _c.mutation.Total(); !ok {
return &ValidationError{Name: "total", err: errors.New(`ent: missing required field "Revision.total"`)}
}
if v, ok := _c.mutation.Total(); ok {
if err := revision.TotalValidator(v); err != nil {
return &ValidationError{Name: "total", err: fmt.Errorf(`ent: validator failed for field "Revision.total": %w`, err)}
}
}
if _, ok := _c.mutation.ExecutedAt(); !ok {
return &ValidationError{Name: "executed_at", err: errors.New(`ent: missing required field "Revision.executed_at"`)}
}
if _, ok := _c.mutation.ExecutionTime(); !ok {
return &ValidationError{Name: "execution_time", err: errors.New(`ent: missing required field "Revision.execution_time"`)}
}
if _, ok := _c.mutation.Hash(); !ok {
return &ValidationError{Name: "hash", err: errors.New(`ent: missing required field "Revision.hash"`)}
}
if _, ok := _c.mutation.OperatorVersion(); !ok {
return &ValidationError{Name: "operator_version", err: errors.New(`ent: missing required field "Revision.operator_version"`)}
}
return nil
}
func (_c *RevisionCreate) sqlSave(ctx context.Context) (*Revision, error) {
if err := _c.check(); err != nil {
return nil, err
}
_node, _spec := _c.createSpec()
if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
return nil, err
}
if _spec.ID.Value != nil {
if id, ok := _spec.ID.Value.(string); ok {
_node.ID = id
} else {
return nil, fmt.Errorf("unexpected Revision.ID type: %T", _spec.ID.Value)
}
}
_c.mutation.id = &_node.ID
_c.mutation.done = true
return _node, nil
}
func (_c *RevisionCreate) createSpec() (*Revision, *sqlgraph.CreateSpec) {
var (
_node = &Revision{config: _c.config}
_spec = sqlgraph.NewCreateSpec(revision.Table, sqlgraph.NewFieldSpec(revision.FieldID, field.TypeString))
)
_spec.Schema = _c.schemaConfig.Revision
_spec.OnConflict = _c.conflict
if id, ok := _c.mutation.ID(); ok {
_node.ID = id
_spec.ID.Value = id
}
if value, ok := _c.mutation.Description(); ok {
_spec.SetField(revision.FieldDescription, field.TypeString, value)
_node.Description = value
}
if value, ok := _c.mutation.GetType(); ok {
_spec.SetField(revision.FieldType, field.TypeUint, value)
_node.Type = value
}
if value, ok := _c.mutation.Applied(); ok {
_spec.SetField(revision.FieldApplied, field.TypeInt, value)
_node.Applied = value
}
if value, ok := _c.mutation.Total(); ok {
_spec.SetField(revision.FieldTotal, field.TypeInt, value)
_node.Total = value
}
if value, ok := _c.mutation.ExecutedAt(); ok {
_spec.SetField(revision.FieldExecutedAt, field.TypeTime, value)
_node.ExecutedAt = value
}
if value, ok := _c.mutation.ExecutionTime(); ok {
_spec.SetField(revision.FieldExecutionTime, field.TypeInt64, value)
_node.ExecutionTime = value
}
if value, ok := _c.mutation.Error(); ok {
_spec.SetField(revision.FieldError, field.TypeString, value)
_node.Error = value
}
if value, ok := _c.mutation.ErrorStmt(); ok {
_spec.SetField(revision.FieldErrorStmt, field.TypeString, value)
_node.ErrorStmt = value
}
if value, ok := _c.mutation.Hash(); ok {
_spec.SetField(revision.FieldHash, field.TypeString, value)
_node.Hash = value
}
if value, ok := _c.mutation.PartialHashes(); ok {
_spec.SetField(revision.FieldPartialHashes, field.TypeJSON, value)
_node.PartialHashes = value
}
if value, ok := _c.mutation.OperatorVersion(); ok {
_spec.SetField(revision.FieldOperatorVersion, field.TypeString, value)
_node.OperatorVersion = value
}
return _node, _spec
}
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
// of the `INSERT` statement. For example:
//
// client.Revision.Create().
// SetDescription(v).
// OnConflict(
// // Update the row with the new values
// // the was proposed for insertion.
// sql.ResolveWithNewValues(),
// ).
// // Override some of the fields with custom
// // update values.
// Update(func(u *ent.RevisionUpsert) {
// SetDescription(v+v).
// }).
// Exec(ctx)
func (_c *RevisionCreate) OnConflict(opts ...sql.ConflictOption) *RevisionUpsertOne {
_c.conflict = opts
return &RevisionUpsertOne{
create: _c,
}
}
// OnConflictColumns calls `OnConflict` and configures the columns
// as conflict target. Using this option is equivalent to using:
//
// client.Revision.Create().
// OnConflict(sql.ConflictColumns(columns...)).
// Exec(ctx)
func (_c *RevisionCreate) OnConflictColumns(columns ...string) *RevisionUpsertOne {
_c.conflict = append(_c.conflict, sql.ConflictColumns(columns...))
return &RevisionUpsertOne{
create: _c,
}
}
type (
// RevisionUpsertOne is the builder for "upsert"-ing
// one Revision node.
RevisionUpsertOne struct {
create *RevisionCreate
}
// RevisionUpsert is the "OnConflict" setter.
RevisionUpsert struct {
*sql.UpdateSet
}
)
// SetType sets the "type" field.
func (u *RevisionUpsert) SetType(v migrate.RevisionType) *RevisionUpsert {
u.Set(revision.FieldType, v)
return u
}
// UpdateType sets the "type" field to the value that was provided on create.
func (u *RevisionUpsert) UpdateType() *RevisionUpsert {
u.SetExcluded(revision.FieldType)
return u
}
// AddType adds v to the "type" field.
func (u *RevisionUpsert) AddType(v migrate.RevisionType) *RevisionUpsert {
u.Add(revision.FieldType, v)
return u
}
// SetApplied sets the "applied" field.
func (u *RevisionUpsert) SetApplied(v int) *RevisionUpsert {
u.Set(revision.FieldApplied, v)
return u
}
// UpdateApplied sets the "applied" field to the value that was provided on create.
func (u *RevisionUpsert) UpdateApplied() *RevisionUpsert {
u.SetExcluded(revision.FieldApplied)
return u
}
// AddApplied adds v to the "applied" field.
func (u *RevisionUpsert) AddApplied(v int) *RevisionUpsert {
u.Add(revision.FieldApplied, v)
return u
}
// SetTotal sets the "total" field.
func (u *RevisionUpsert) SetTotal(v int) *RevisionUpsert {
u.Set(revision.FieldTotal, v)
return u
}
// UpdateTotal sets the "total" field to the value that was provided on create.
func (u *RevisionUpsert) UpdateTotal() *RevisionUpsert {
u.SetExcluded(revision.FieldTotal)
return u
}
// AddTotal adds v to the "total" field.
func (u *RevisionUpsert) AddTotal(v int) *RevisionUpsert {
u.Add(revision.FieldTotal, v)
return u
}
// SetExecutionTime sets the "execution_time" field.
func (u *RevisionUpsert) SetExecutionTime(v time.Duration) *RevisionUpsert {
u.Set(revision.FieldExecutionTime, v)
return u
}
// UpdateExecutionTime sets the "execution_time" field to the value that was provided on create.
func (u *RevisionUpsert) UpdateExecutionTime() *RevisionUpsert {
u.SetExcluded(revision.FieldExecutionTime)
return u
}
// AddExecutionTime adds v to the "execution_time" field.
func (u *RevisionUpsert) AddExecutionTime(v time.Duration) *RevisionUpsert {
u.Add(revision.FieldExecutionTime, v)
return u
}
// SetError sets the "error" field.
func (u *RevisionUpsert) SetError(v string) *RevisionUpsert {
u.Set(revision.FieldError, v)
return u
}
// UpdateError sets the "error" field to the value that was provided on create.
func (u *RevisionUpsert) UpdateError() *RevisionUpsert {
u.SetExcluded(revision.FieldError)
return u
}
// ClearError clears the value of the "error" field.
func (u *RevisionUpsert) ClearError() *RevisionUpsert {
u.SetNull(revision.FieldError)
return u
}
// SetErrorStmt sets the "error_stmt" field.
func (u *RevisionUpsert) SetErrorStmt(v string) *RevisionUpsert {
u.Set(revision.FieldErrorStmt, v)
return u
}
// UpdateErrorStmt sets the "error_stmt" field to the value that was provided on create.
func (u *RevisionUpsert) UpdateErrorStmt() *RevisionUpsert {
u.SetExcluded(revision.FieldErrorStmt)
return u
}
// ClearErrorStmt clears the value of the "error_stmt" field.
func (u *RevisionUpsert) ClearErrorStmt() *RevisionUpsert {
u.SetNull(revision.FieldErrorStmt)
return u
}
// SetHash sets the "hash" field.
func (u *RevisionUpsert) SetHash(v string) *RevisionUpsert {
u.Set(revision.FieldHash, v)
return u
}
// UpdateHash sets the "hash" field to the value that was provided on create.
func (u *RevisionUpsert) UpdateHash() *RevisionUpsert {
u.SetExcluded(revision.FieldHash)
return u
}
// SetPartialHashes sets the "partial_hashes" field.
func (u *RevisionUpsert) SetPartialHashes(v []string) *RevisionUpsert {
u.Set(revision.FieldPartialHashes, v)
return u
}
// UpdatePartialHashes sets the "partial_hashes" field to the value that was provided on create.
func (u *RevisionUpsert) UpdatePartialHashes() *RevisionUpsert {
u.SetExcluded(revision.FieldPartialHashes)
return u
}
// ClearPartialHashes clears the value of the "partial_hashes" field.
func (u *RevisionUpsert) ClearPartialHashes() *RevisionUpsert {
u.SetNull(revision.FieldPartialHashes)
return u
}
// SetOperatorVersion sets the "operator_version" field.
func (u *RevisionUpsert) SetOperatorVersion(v string) *RevisionUpsert {
u.Set(revision.FieldOperatorVersion, v)
return u
}
// UpdateOperatorVersion sets the "operator_version" field to the value that was provided on create.
func (u *RevisionUpsert) UpdateOperatorVersion() *RevisionUpsert {
u.SetExcluded(revision.FieldOperatorVersion)
return u
}
// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field.
// Using this option is equivalent to using:
//
// client.Revision.Create().
// OnConflict(
// sql.ResolveWithNewValues(),
// sql.ResolveWith(func(u *sql.UpdateSet) {
// u.SetIgnore(revision.FieldID)
// }),
// ).
// Exec(ctx)
func (u *RevisionUpsertOne) UpdateNewValues() *RevisionUpsertOne {
u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
if _, exists := u.create.mutation.ID(); exists {
s.SetIgnore(revision.FieldID)
}
if _, exists := u.create.mutation.Description(); exists {
s.SetIgnore(revision.FieldDescription)
}
if _, exists := u.create.mutation.ExecutedAt(); exists {
s.SetIgnore(revision.FieldExecutedAt)
}
}))
return u
}
// Ignore sets each column to itself in case of conflict.
// Using this option is equivalent to using:
//
// client.Revision.Create().
// OnConflict(sql.ResolveWithIgnore()).
// Exec(ctx)
func (u *RevisionUpsertOne) Ignore() *RevisionUpsertOne {
u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
return u
}
// DoNothing configures the conflict_action to `DO NOTHING`.
// Supported only by SQLite and PostgreSQL.
func (u *RevisionUpsertOne) DoNothing() *RevisionUpsertOne {
u.create.conflict = append(u.create.conflict, sql.DoNothing())
return u
}
// Update allows overriding fields `UPDATE` values. See the RevisionCreate.OnConflict
// documentation for more info.
func (u *RevisionUpsertOne) Update(set func(*RevisionUpsert)) *RevisionUpsertOne {
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
set(&RevisionUpsert{UpdateSet: update})
}))
return u
}
// SetType sets the "type" field.
func (u *RevisionUpsertOne) SetType(v migrate.RevisionType) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.SetType(v)
})
}
// AddType adds v to the "type" field.
func (u *RevisionUpsertOne) AddType(v migrate.RevisionType) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.AddType(v)
})
}
// UpdateType sets the "type" field to the value that was provided on create.
func (u *RevisionUpsertOne) UpdateType() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.UpdateType()
})
}
// SetApplied sets the "applied" field.
func (u *RevisionUpsertOne) SetApplied(v int) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.SetApplied(v)
})
}
// AddApplied adds v to the "applied" field.
func (u *RevisionUpsertOne) AddApplied(v int) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.AddApplied(v)
})
}
// UpdateApplied sets the "applied" field to the value that was provided on create.
func (u *RevisionUpsertOne) UpdateApplied() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.UpdateApplied()
})
}
// SetTotal sets the "total" field.
func (u *RevisionUpsertOne) SetTotal(v int) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.SetTotal(v)
})
}
// AddTotal adds v to the "total" field.
func (u *RevisionUpsertOne) AddTotal(v int) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.AddTotal(v)
})
}
// UpdateTotal sets the "total" field to the value that was provided on create.
func (u *RevisionUpsertOne) UpdateTotal() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.UpdateTotal()
})
}
// SetExecutionTime sets the "execution_time" field.
func (u *RevisionUpsertOne) SetExecutionTime(v time.Duration) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.SetExecutionTime(v)
})
}
// AddExecutionTime adds v to the "execution_time" field.
func (u *RevisionUpsertOne) AddExecutionTime(v time.Duration) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.AddExecutionTime(v)
})
}
// UpdateExecutionTime sets the "execution_time" field to the value that was provided on create.
func (u *RevisionUpsertOne) UpdateExecutionTime() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.UpdateExecutionTime()
})
}
// SetError sets the "error" field.
func (u *RevisionUpsertOne) SetError(v string) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.SetError(v)
})
}
// UpdateError sets the "error" field to the value that was provided on create.
func (u *RevisionUpsertOne) UpdateError() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.UpdateError()
})
}
// ClearError clears the value of the "error" field.
func (u *RevisionUpsertOne) ClearError() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.ClearError()
})
}
// SetErrorStmt sets the "error_stmt" field.
func (u *RevisionUpsertOne) SetErrorStmt(v string) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.SetErrorStmt(v)
})
}
// UpdateErrorStmt sets the "error_stmt" field to the value that was provided on create.
func (u *RevisionUpsertOne) UpdateErrorStmt() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.UpdateErrorStmt()
})
}
// ClearErrorStmt clears the value of the "error_stmt" field.
func (u *RevisionUpsertOne) ClearErrorStmt() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.ClearErrorStmt()
})
}
// SetHash sets the "hash" field.
func (u *RevisionUpsertOne) SetHash(v string) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.SetHash(v)
})
}
// UpdateHash sets the "hash" field to the value that was provided on create.
func (u *RevisionUpsertOne) UpdateHash() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.UpdateHash()
})
}
// SetPartialHashes sets the "partial_hashes" field.
func (u *RevisionUpsertOne) SetPartialHashes(v []string) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.SetPartialHashes(v)
})
}
// UpdatePartialHashes sets the "partial_hashes" field to the value that was provided on create.
func (u *RevisionUpsertOne) UpdatePartialHashes() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.UpdatePartialHashes()
})
}
// ClearPartialHashes clears the value of the "partial_hashes" field.
func (u *RevisionUpsertOne) ClearPartialHashes() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.ClearPartialHashes()
})
}
// SetOperatorVersion sets the "operator_version" field.
func (u *RevisionUpsertOne) SetOperatorVersion(v string) *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.SetOperatorVersion(v)
})
}
// UpdateOperatorVersion sets the "operator_version" field to the value that was provided on create.
func (u *RevisionUpsertOne) UpdateOperatorVersion() *RevisionUpsertOne {
return u.Update(func(s *RevisionUpsert) {
s.UpdateOperatorVersion()
})
}
// Exec executes the query.
func (u *RevisionUpsertOne) Exec(ctx context.Context) error {
if len(u.create.conflict) == 0 {
return errors.New("ent: missing options for RevisionCreate.OnConflict")
}
return u.create.Exec(ctx)
}
// ExecX is like Exec, but panics if an error occurs.
func (u *RevisionUpsertOne) ExecX(ctx context.Context) {
if err := u.create.Exec(ctx); err != nil {
panic(err)
}
}
// Exec executes the UPSERT query and returns the inserted/updated ID.
func (u *RevisionUpsertOne) ID(ctx context.Context) (id string, err error) {
if u.create.driver.Dialect() == dialect.MySQL {
// In case of "ON CONFLICT", there is no way to get back non-numeric ID
// fields from the database since MySQL does not support the RETURNING clause.
return id, errors.New("ent: RevisionUpsertOne.ID is not supported by MySQL driver. Use RevisionUpsertOne.Exec instead")
}
node, err := u.create.Save(ctx)
if err != nil {
return id, err
}
return node.ID, nil
}
// IDX is like ID, but panics if an error occurs.
func (u *RevisionUpsertOne) IDX(ctx context.Context) string {
id, err := u.ID(ctx)
if err != nil {
panic(err)
}
return id
}
// RevisionCreateBulk is the builder for creating many Revision entities in bulk.
type RevisionCreateBulk struct {
config
err error
builders []*RevisionCreate
conflict []sql.ConflictOption
}
// Save creates the Revision entities in the database.
func (_c *RevisionCreateBulk) Save(ctx context.Context) ([]*Revision, error) {
if _c.err != nil {
return nil, _c.err
}
specs := make([]*sqlgraph.CreateSpec, len(_c.builders))
nodes := make([]*Revision, len(_c.builders))
mutators := make([]Mutator, len(_c.builders))
for i := range _c.builders {
func(i int, root context.Context) {
builder := _c.builders[i]
builder.defaults()
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutation, ok := m.(*RevisionMutation)
if !ok {
return nil, fmt.Errorf("unexpected mutation type %T", m)
}
if err := builder.check(); err != nil {
return nil, err
}
builder.mutation = mutation
var err error
nodes[i], specs[i] = builder.createSpec()
if i < len(mutators)-1 {
_, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation)
} else {
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
spec.OnConflict = _c.conflict
// Invoke the actual operation on the latest mutation in the chain.
if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
}
}
if err != nil {
return nil, err
}
mutation.id = &nodes[i].ID
mutation.done = true
return nodes[i], nil
})
for i := len(builder.hooks) - 1; i >= 0; i-- {
mut = builder.hooks[i](mut)
}
mutators[i] = mut
}(i, ctx)
}
if len(mutators) > 0 {
if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil {
return nil, err
}
}
return nodes, nil
}
// SaveX is like Save, but panics if an error occurs.
func (_c *RevisionCreateBulk) SaveX(ctx context.Context) []*Revision {
v, err := _c.Save(ctx)
if err != nil {
panic(err)
}
return v
}
// Exec executes the query.
func (_c *RevisionCreateBulk) Exec(ctx context.Context) error {
_, err := _c.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_c *RevisionCreateBulk) ExecX(ctx context.Context) {
if err := _c.Exec(ctx); err != nil {
panic(err)
}
}
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
// of the `INSERT` statement. For example:
//
// client.Revision.CreateBulk(builders...).
// OnConflict(
// // Update the row with the new values
// // the was proposed for insertion.
// sql.ResolveWithNewValues(),
// ).
// // Override some of the fields with custom
// // update values.
// Update(func(u *ent.RevisionUpsert) {
// SetDescription(v+v).
// }).
// Exec(ctx)
func (_c *RevisionCreateBulk) OnConflict(opts ...sql.ConflictOption) *RevisionUpsertBulk {
_c.conflict = opts
return &RevisionUpsertBulk{
create: _c,
}
}
// OnConflictColumns calls `OnConflict` and configures the columns
// as conflict target. Using this option is equivalent to using:
//
// client.Revision.Create().
// OnConflict(sql.ConflictColumns(columns...)).
// Exec(ctx)
func (_c *RevisionCreateBulk) OnConflictColumns(columns ...string) *RevisionUpsertBulk {
_c.conflict = append(_c.conflict, sql.ConflictColumns(columns...))
return &RevisionUpsertBulk{
create: _c,
}
}
// RevisionUpsertBulk is the builder for "upsert"-ing
// a bulk of Revision nodes.
type RevisionUpsertBulk struct {
create *RevisionCreateBulk
}
// UpdateNewValues updates the mutable fields using the new values that
// were set on create. Using this option is equivalent to using:
//
// client.Revision.Create().
// OnConflict(
// sql.ResolveWithNewValues(),
// sql.ResolveWith(func(u *sql.UpdateSet) {
// u.SetIgnore(revision.FieldID)
// }),
// ).
// Exec(ctx)
func (u *RevisionUpsertBulk) UpdateNewValues() *RevisionUpsertBulk {
u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
for _, b := range u.create.builders {
if _, exists := b.mutation.ID(); exists {
s.SetIgnore(revision.FieldID)
}
if _, exists := b.mutation.Description(); exists {
s.SetIgnore(revision.FieldDescription)
}
if _, exists := b.mutation.ExecutedAt(); exists {
s.SetIgnore(revision.FieldExecutedAt)
}
}
}))
return u
}
// Ignore sets each column to itself in case of conflict.
// Using this option is equivalent to using:
//
// client.Revision.Create().
// OnConflict(sql.ResolveWithIgnore()).
// Exec(ctx)
func (u *RevisionUpsertBulk) Ignore() *RevisionUpsertBulk {
u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
return u
}
// DoNothing configures the conflict_action to `DO NOTHING`.
// Supported only by SQLite and PostgreSQL.
func (u *RevisionUpsertBulk) DoNothing() *RevisionUpsertBulk {
u.create.conflict = append(u.create.conflict, sql.DoNothing())
return u
}
// Update allows overriding fields `UPDATE` values. See the RevisionCreateBulk.OnConflict
// documentation for more info.
func (u *RevisionUpsertBulk) Update(set func(*RevisionUpsert)) *RevisionUpsertBulk {
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
set(&RevisionUpsert{UpdateSet: update})
}))
return u
}
// SetType sets the "type" field.
func (u *RevisionUpsertBulk) SetType(v migrate.RevisionType) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.SetType(v)
})
}
// AddType adds v to the "type" field.
func (u *RevisionUpsertBulk) AddType(v migrate.RevisionType) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.AddType(v)
})
}
// UpdateType sets the "type" field to the value that was provided on create.
func (u *RevisionUpsertBulk) UpdateType() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.UpdateType()
})
}
// SetApplied sets the "applied" field.
func (u *RevisionUpsertBulk) SetApplied(v int) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.SetApplied(v)
})
}
// AddApplied adds v to the "applied" field.
func (u *RevisionUpsertBulk) AddApplied(v int) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.AddApplied(v)
})
}
// UpdateApplied sets the "applied" field to the value that was provided on create.
func (u *RevisionUpsertBulk) UpdateApplied() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.UpdateApplied()
})
}
// SetTotal sets the "total" field.
func (u *RevisionUpsertBulk) SetTotal(v int) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.SetTotal(v)
})
}
// AddTotal adds v to the "total" field.
func (u *RevisionUpsertBulk) AddTotal(v int) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.AddTotal(v)
})
}
// UpdateTotal sets the "total" field to the value that was provided on create.
func (u *RevisionUpsertBulk) UpdateTotal() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.UpdateTotal()
})
}
// SetExecutionTime sets the "execution_time" field.
func (u *RevisionUpsertBulk) SetExecutionTime(v time.Duration) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.SetExecutionTime(v)
})
}
// AddExecutionTime adds v to the "execution_time" field.
func (u *RevisionUpsertBulk) AddExecutionTime(v time.Duration) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.AddExecutionTime(v)
})
}
// UpdateExecutionTime sets the "execution_time" field to the value that was provided on create.
func (u *RevisionUpsertBulk) UpdateExecutionTime() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.UpdateExecutionTime()
})
}
// SetError sets the "error" field.
func (u *RevisionUpsertBulk) SetError(v string) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.SetError(v)
})
}
// UpdateError sets the "error" field to the value that was provided on create.
func (u *RevisionUpsertBulk) UpdateError() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.UpdateError()
})
}
// ClearError clears the value of the "error" field.
func (u *RevisionUpsertBulk) ClearError() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.ClearError()
})
}
// SetErrorStmt sets the "error_stmt" field.
func (u *RevisionUpsertBulk) SetErrorStmt(v string) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.SetErrorStmt(v)
})
}
// UpdateErrorStmt sets the "error_stmt" field to the value that was provided on create.
func (u *RevisionUpsertBulk) UpdateErrorStmt() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.UpdateErrorStmt()
})
}
// ClearErrorStmt clears the value of the "error_stmt" field.
func (u *RevisionUpsertBulk) ClearErrorStmt() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.ClearErrorStmt()
})
}
// SetHash sets the "hash" field.
func (u *RevisionUpsertBulk) SetHash(v string) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.SetHash(v)
})
}
// UpdateHash sets the "hash" field to the value that was provided on create.
func (u *RevisionUpsertBulk) UpdateHash() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.UpdateHash()
})
}
// SetPartialHashes sets the "partial_hashes" field.
func (u *RevisionUpsertBulk) SetPartialHashes(v []string) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.SetPartialHashes(v)
})
}
// UpdatePartialHashes sets the "partial_hashes" field to the value that was provided on create.
func (u *RevisionUpsertBulk) UpdatePartialHashes() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.UpdatePartialHashes()
})
}
// ClearPartialHashes clears the value of the "partial_hashes" field.
func (u *RevisionUpsertBulk) ClearPartialHashes() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.ClearPartialHashes()
})
}
// SetOperatorVersion sets the "operator_version" field.
func (u *RevisionUpsertBulk) SetOperatorVersion(v string) *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.SetOperatorVersion(v)
})
}
// UpdateOperatorVersion sets the "operator_version" field to the value that was provided on create.
func (u *RevisionUpsertBulk) UpdateOperatorVersion() *RevisionUpsertBulk {
return u.Update(func(s *RevisionUpsert) {
s.UpdateOperatorVersion()
})
}
// Exec executes the query.
func (u *RevisionUpsertBulk) Exec(ctx context.Context) error {
if u.create.err != nil {
return u.create.err
}
for i, b := range u.create.builders {
if len(b.conflict) != 0 {
return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the RevisionCreateBulk instead", i)
}
}
if len(u.create.conflict) == 0 {
return errors.New("ent: missing options for RevisionCreateBulk.OnConflict")
}
return u.create.Exec(ctx)
}
// ExecX is like Exec, but panics if an error occurs.
func (u *RevisionUpsertBulk) ExecX(ctx context.Context) {
if err := u.create.Exec(ctx); err != nil {
panic(err)
}
}
================================================
FILE: cmd/atlas/internal/migrate/ent/revision_delete.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package ent
import (
"context"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/internal"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/predicate"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
)
// RevisionDelete is the builder for deleting a Revision entity.
type RevisionDelete struct {
config
hooks []Hook
mutation *RevisionMutation
}
// Where appends a list predicates to the RevisionDelete builder.
func (_d *RevisionDelete) Where(ps ...predicate.Revision) *RevisionDelete {
_d.mutation.Where(ps...)
return _d
}
// Exec executes the deletion query and returns how many vertices were deleted.
func (_d *RevisionDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
}
// ExecX is like Exec, but panics if an error occurs.
func (_d *RevisionDelete) ExecX(ctx context.Context) int {
n, err := _d.Exec(ctx)
if err != nil {
panic(err)
}
return n
}
func (_d *RevisionDelete) sqlExec(ctx context.Context) (int, error) {
_spec := sqlgraph.NewDeleteSpec(revision.Table, sqlgraph.NewFieldSpec(revision.FieldID, field.TypeString))
_spec.Node.Schema = _d.schemaConfig.Revision
ctx = internal.NewSchemaConfigContext(ctx, _d.schemaConfig)
if ps := _d.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)
if err != nil && sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
_d.mutation.done = true
return affected, err
}
// RevisionDeleteOne is the builder for deleting a single Revision entity.
type RevisionDeleteOne struct {
_d *RevisionDelete
}
// Where appends a list predicates to the RevisionDelete builder.
func (_d *RevisionDeleteOne) Where(ps ...predicate.Revision) *RevisionDeleteOne {
_d._d.mutation.Where(ps...)
return _d
}
// Exec executes the deletion query.
func (_d *RevisionDeleteOne) Exec(ctx context.Context) error {
n, err := _d._d.Exec(ctx)
switch {
case err != nil:
return err
case n == 0:
return &NotFoundError{revision.Label}
default:
return nil
}
}
// ExecX is like Exec, but panics if an error occurs.
func (_d *RevisionDeleteOne) ExecX(ctx context.Context) {
if err := _d.Exec(ctx); err != nil {
panic(err)
}
}
================================================
FILE: cmd/atlas/internal/migrate/ent/revision_query.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package ent
import (
"context"
"fmt"
"math"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/internal"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/predicate"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
)
// RevisionQuery is the builder for querying Revision entities.
type RevisionQuery struct {
config
ctx *QueryContext
order []revision.OrderOption
inters []Interceptor
predicates []predicate.Revision
// intermediate query (i.e. traversal path).
sql *sql.Selector
path func(context.Context) (*sql.Selector, error)
}
// Where adds a new predicate for the RevisionQuery builder.
func (_q *RevisionQuery) Where(ps ...predicate.Revision) *RevisionQuery {
_q.predicates = append(_q.predicates, ps...)
return _q
}
// Limit the number of records to be returned by this query.
func (_q *RevisionQuery) Limit(limit int) *RevisionQuery {
_q.ctx.Limit = &limit
return _q
}
// Offset to start from.
func (_q *RevisionQuery) Offset(offset int) *RevisionQuery {
_q.ctx.Offset = &offset
return _q
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (_q *RevisionQuery) Unique(unique bool) *RevisionQuery {
_q.ctx.Unique = &unique
return _q
}
// Order specifies how the records should be ordered.
func (_q *RevisionQuery) Order(o ...revision.OrderOption) *RevisionQuery {
_q.order = append(_q.order, o...)
return _q
}
// First returns the first Revision entity from the query.
// Returns a *NotFoundError when no Revision was found.
func (_q *RevisionQuery) First(ctx context.Context) (*Revision, error) {
nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst))
if err != nil {
return nil, err
}
if len(nodes) == 0 {
return nil, &NotFoundError{revision.Label}
}
return nodes[0], nil
}
// FirstX is like First, but panics if an error occurs.
func (_q *RevisionQuery) FirstX(ctx context.Context) *Revision {
node, err := _q.First(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return node
}
// FirstID returns the first Revision ID from the query.
// Returns a *NotFoundError when no Revision ID was found.
func (_q *RevisionQuery) FirstID(ctx context.Context) (id string, err error) {
var ids []string
if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil {
return
}
if len(ids) == 0 {
err = &NotFoundError{revision.Label}
return
}
return ids[0], nil
}
// FirstIDX is like FirstID, but panics if an error occurs.
func (_q *RevisionQuery) FirstIDX(ctx context.Context) string {
id, err := _q.FirstID(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return id
}
// Only returns a single Revision entity found by the query, ensuring it only returns one.
// Returns a *NotSingularError when more than one Revision entity is found.
// Returns a *NotFoundError when no Revision entities are found.
func (_q *RevisionQuery) Only(ctx context.Context) (*Revision, error) {
nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly))
if err != nil {
return nil, err
}
switch len(nodes) {
case 1:
return nodes[0], nil
case 0:
return nil, &NotFoundError{revision.Label}
default:
return nil, &NotSingularError{revision.Label}
}
}
// OnlyX is like Only, but panics if an error occurs.
func (_q *RevisionQuery) OnlyX(ctx context.Context) *Revision {
node, err := _q.Only(ctx)
if err != nil {
panic(err)
}
return node
}
// OnlyID is like Only, but returns the only Revision ID in the query.
// Returns a *NotSingularError when more than one Revision ID is found.
// Returns a *NotFoundError when no entities are found.
func (_q *RevisionQuery) OnlyID(ctx context.Context) (id string, err error) {
var ids []string
if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil {
return
}
switch len(ids) {
case 1:
id = ids[0]
case 0:
err = &NotFoundError{revision.Label}
default:
err = &NotSingularError{revision.Label}
}
return
}
// OnlyIDX is like OnlyID, but panics if an error occurs.
func (_q *RevisionQuery) OnlyIDX(ctx context.Context) string {
id, err := _q.OnlyID(ctx)
if err != nil {
panic(err)
}
return id
}
// All executes the query and returns a list of Revisions.
func (_q *RevisionQuery) All(ctx context.Context) ([]*Revision, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll)
if err := _q.prepareQuery(ctx); err != nil {
return nil, err
}
qr := querierAll[[]*Revision, *RevisionQuery]()
return withInterceptors[[]*Revision](ctx, _q, qr, _q.inters)
}
// AllX is like All, but panics if an error occurs.
func (_q *RevisionQuery) AllX(ctx context.Context) []*Revision {
nodes, err := _q.All(ctx)
if err != nil {
panic(err)
}
return nodes
}
// IDs executes the query and returns a list of Revision IDs.
func (_q *RevisionQuery) IDs(ctx context.Context) (ids []string, err error) {
if _q.ctx.Unique == nil && _q.path != nil {
_q.Unique(true)
}
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs)
if err = _q.Select(revision.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
return ids, nil
}
// IDsX is like IDs, but panics if an error occurs.
func (_q *RevisionQuery) IDsX(ctx context.Context) []string {
ids, err := _q.IDs(ctx)
if err != nil {
panic(err)
}
return ids
}
// Count returns the count of the given query.
func (_q *RevisionQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount)
if err := _q.prepareQuery(ctx); err != nil {
return 0, err
}
return withInterceptors[int](ctx, _q, querierCount[*RevisionQuery](), _q.inters)
}
// CountX is like Count, but panics if an error occurs.
func (_q *RevisionQuery) CountX(ctx context.Context) int {
count, err := _q.Count(ctx)
if err != nil {
panic(err)
}
return count
}
// Exist returns true if the query has elements in the graph.
func (_q *RevisionQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist)
switch _, err := _q.FirstID(ctx); {
case IsNotFound(err):
return false, nil
case err != nil:
return false, fmt.Errorf("ent: check existence: %w", err)
default:
return true, nil
}
}
// ExistX is like Exist, but panics if an error occurs.
func (_q *RevisionQuery) ExistX(ctx context.Context) bool {
exist, err := _q.Exist(ctx)
if err != nil {
panic(err)
}
return exist
}
// Clone returns a duplicate of the RevisionQuery builder, including all associated steps. It can be
// used to prepare common query builders and use them differently after the clone is made.
func (_q *RevisionQuery) Clone() *RevisionQuery {
if _q == nil {
return nil
}
return &RevisionQuery{
config: _q.config,
ctx: _q.ctx.Clone(),
order: append([]revision.OrderOption{}, _q.order...),
inters: append([]Interceptor{}, _q.inters...),
predicates: append([]predicate.Revision{}, _q.predicates...),
// clone intermediate query.
sql: _q.sql.Clone(),
path: _q.path,
}
}
// GroupBy is used to group vertices by one or more fields/columns.
// It is often used with aggregate functions, like: count, max, mean, min, sum.
//
// Example:
//
// var v []struct {
// Description string `json:"description,omitempty"`
// Count int `json:"count,omitempty"`
// }
//
// client.Revision.Query().
// GroupBy(revision.FieldDescription).
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (_q *RevisionQuery) GroupBy(field string, fields ...string) *RevisionGroupBy {
_q.ctx.Fields = append([]string{field}, fields...)
grbuild := &RevisionGroupBy{build: _q}
grbuild.flds = &_q.ctx.Fields
grbuild.label = revision.Label
grbuild.scan = grbuild.Scan
return grbuild
}
// Select allows the selection one or more fields/columns for the given query,
// instead of selecting all fields in the entity.
//
// Example:
//
// var v []struct {
// Description string `json:"description,omitempty"`
// }
//
// client.Revision.Query().
// Select(revision.FieldDescription).
// Scan(ctx, &v)
func (_q *RevisionQuery) Select(fields ...string) *RevisionSelect {
_q.ctx.Fields = append(_q.ctx.Fields, fields...)
sbuild := &RevisionSelect{RevisionQuery: _q}
sbuild.label = revision.Label
sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan
return sbuild
}
// Aggregate returns a RevisionSelect configured with the given aggregations.
func (_q *RevisionQuery) Aggregate(fns ...AggregateFunc) *RevisionSelect {
return _q.Select().Aggregate(fns...)
}
func (_q *RevisionQuery) prepareQuery(ctx context.Context) error {
for _, inter := range _q.inters {
if inter == nil {
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
}
if trv, ok := inter.(Traverser); ok {
if err := trv.Traverse(ctx, _q); err != nil {
return err
}
}
}
for _, f := range _q.ctx.Fields {
if !revision.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
}
if _q.path != nil {
prev, err := _q.path(ctx)
if err != nil {
return err
}
_q.sql = prev
}
return nil
}
func (_q *RevisionQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Revision, error) {
var (
nodes = []*Revision{}
_spec = _q.querySpec()
)
_spec.ScanValues = func(columns []string) ([]any, error) {
return (*Revision).scanValues(nil, columns)
}
_spec.Assign = func(columns []string, values []any) error {
node := &Revision{config: _q.config}
nodes = append(nodes, node)
return node.assignValues(columns, values)
}
_spec.Node.Schema = _q.schemaConfig.Revision
ctx = internal.NewSchemaConfigContext(ctx, _q.schemaConfig)
for i := range hooks {
hooks[i](ctx, _spec)
}
if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil {
return nil, err
}
if len(nodes) == 0 {
return nodes, nil
}
return nodes, nil
}
func (_q *RevisionQuery) sqlCount(ctx context.Context) (int, error) {
_spec := _q.querySpec()
_spec.Node.Schema = _q.schemaConfig.Revision
ctx = internal.NewSchemaConfigContext(ctx, _q.schemaConfig)
_spec.Node.Columns = _q.ctx.Fields
if len(_q.ctx.Fields) > 0 {
_spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique
}
return sqlgraph.CountNodes(ctx, _q.driver, _spec)
}
func (_q *RevisionQuery) querySpec() *sqlgraph.QuerySpec {
_spec := sqlgraph.NewQuerySpec(revision.Table, revision.Columns, sqlgraph.NewFieldSpec(revision.FieldID, field.TypeString))
_spec.From = _q.sql
if unique := _q.ctx.Unique; unique != nil {
_spec.Unique = *unique
} else if _q.path != nil {
_spec.Unique = true
}
if fields := _q.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, revision.FieldID)
for i := range fields {
if fields[i] != revision.FieldID {
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
}
}
}
if ps := _q.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if limit := _q.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := _q.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := _q.order; len(ps) > 0 {
_spec.Order = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
return _spec
}
func (_q *RevisionQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(_q.driver.Dialect())
t1 := builder.Table(revision.Table)
columns := _q.ctx.Fields
if len(columns) == 0 {
columns = revision.Columns
}
selector := builder.Select(t1.Columns(columns...)...).From(t1)
if _q.sql != nil {
selector = _q.sql
selector.Select(selector.Columns(columns...)...)
}
if _q.ctx.Unique != nil && *_q.ctx.Unique {
selector.Distinct()
}
t1.Schema(_q.schemaConfig.Revision)
ctx = internal.NewSchemaConfigContext(ctx, _q.schemaConfig)
selector.WithContext(ctx)
for _, p := range _q.predicates {
p(selector)
}
for _, p := range _q.order {
p(selector)
}
if offset := _q.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := _q.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
}
// RevisionGroupBy is the group-by builder for Revision entities.
type RevisionGroupBy struct {
selector
build *RevisionQuery
}
// Aggregate adds the given aggregation functions to the group-by query.
func (_g *RevisionGroupBy) Aggregate(fns ...AggregateFunc) *RevisionGroupBy {
_g.fns = append(_g.fns, fns...)
return _g
}
// Scan applies the selector query and scans the result into the given value.
func (_g *RevisionGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy)
if err := _g.build.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*RevisionQuery, *RevisionGroupBy](ctx, _g.build, _g, _g.build.inters, v)
}
func (_g *RevisionGroupBy) sqlScan(ctx context.Context, root *RevisionQuery, v any) error {
selector := root.sqlQuery(ctx).Select()
aggregation := make([]string, 0, len(_g.fns))
for _, fn := range _g.fns {
aggregation = append(aggregation, fn(selector))
}
if len(selector.SelectedColumns()) == 0 {
columns := make([]string, 0, len(*_g.flds)+len(_g.fns))
for _, f := range *_g.flds {
columns = append(columns, selector.C(f))
}
columns = append(columns, aggregation...)
selector.Select(columns...)
}
selector.GroupBy(selector.Columns(*_g.flds...)...)
if err := selector.Err(); err != nil {
return err
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := _g.build.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}
// RevisionSelect is the builder for selecting fields of Revision entities.
type RevisionSelect struct {
*RevisionQuery
selector
}
// Aggregate adds the given aggregation functions to the selector query.
func (_s *RevisionSelect) Aggregate(fns ...AggregateFunc) *RevisionSelect {
_s.fns = append(_s.fns, fns...)
return _s
}
// Scan applies the selector query and scans the result into the given value.
func (_s *RevisionSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect)
if err := _s.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*RevisionQuery, *RevisionSelect](ctx, _s.RevisionQuery, _s, _s.inters, v)
}
func (_s *RevisionSelect) sqlScan(ctx context.Context, root *RevisionQuery, v any) error {
selector := root.sqlQuery(ctx)
aggregation := make([]string, 0, len(_s.fns))
for _, fn := range _s.fns {
aggregation = append(aggregation, fn(selector))
}
switch n := len(*_s.selector.flds); {
case n == 0 && len(aggregation) > 0:
selector.Select(aggregation...)
case n != 0 && len(aggregation) > 0:
selector.AppendSelect(aggregation...)
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := _s.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}
================================================
FILE: cmd/atlas/internal/migrate/ent/revision_update.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package ent
import (
"context"
"errors"
"fmt"
"time"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/internal"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/predicate"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"ariga.io/atlas/sql/migrate"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/dialect/sql/sqljson"
"entgo.io/ent/schema/field"
)
// RevisionUpdate is the builder for updating Revision entities.
type RevisionUpdate struct {
config
hooks []Hook
mutation *RevisionMutation
}
// Where appends a list predicates to the RevisionUpdate builder.
func (_u *RevisionUpdate) Where(ps ...predicate.Revision) *RevisionUpdate {
_u.mutation.Where(ps...)
return _u
}
// SetType sets the "type" field.
func (_u *RevisionUpdate) SetType(v migrate.RevisionType) *RevisionUpdate {
_u.mutation.ResetType()
_u.mutation.SetType(v)
return _u
}
// SetNillableType sets the "type" field if the given value is not nil.
func (_u *RevisionUpdate) SetNillableType(v *migrate.RevisionType) *RevisionUpdate {
if v != nil {
_u.SetType(*v)
}
return _u
}
// AddType adds value to the "type" field.
func (_u *RevisionUpdate) AddType(v migrate.RevisionType) *RevisionUpdate {
_u.mutation.AddType(v)
return _u
}
// SetApplied sets the "applied" field.
func (_u *RevisionUpdate) SetApplied(v int) *RevisionUpdate {
_u.mutation.ResetApplied()
_u.mutation.SetApplied(v)
return _u
}
// SetNillableApplied sets the "applied" field if the given value is not nil.
func (_u *RevisionUpdate) SetNillableApplied(v *int) *RevisionUpdate {
if v != nil {
_u.SetApplied(*v)
}
return _u
}
// AddApplied adds value to the "applied" field.
func (_u *RevisionUpdate) AddApplied(v int) *RevisionUpdate {
_u.mutation.AddApplied(v)
return _u
}
// SetTotal sets the "total" field.
func (_u *RevisionUpdate) SetTotal(v int) *RevisionUpdate {
_u.mutation.ResetTotal()
_u.mutation.SetTotal(v)
return _u
}
// SetNillableTotal sets the "total" field if the given value is not nil.
func (_u *RevisionUpdate) SetNillableTotal(v *int) *RevisionUpdate {
if v != nil {
_u.SetTotal(*v)
}
return _u
}
// AddTotal adds value to the "total" field.
func (_u *RevisionUpdate) AddTotal(v int) *RevisionUpdate {
_u.mutation.AddTotal(v)
return _u
}
// SetExecutionTime sets the "execution_time" field.
func (_u *RevisionUpdate) SetExecutionTime(v time.Duration) *RevisionUpdate {
_u.mutation.ResetExecutionTime()
_u.mutation.SetExecutionTime(v)
return _u
}
// SetNillableExecutionTime sets the "execution_time" field if the given value is not nil.
func (_u *RevisionUpdate) SetNillableExecutionTime(v *time.Duration) *RevisionUpdate {
if v != nil {
_u.SetExecutionTime(*v)
}
return _u
}
// AddExecutionTime adds value to the "execution_time" field.
func (_u *RevisionUpdate) AddExecutionTime(v time.Duration) *RevisionUpdate {
_u.mutation.AddExecutionTime(v)
return _u
}
// SetError sets the "error" field.
func (_u *RevisionUpdate) SetError(v string) *RevisionUpdate {
_u.mutation.SetError(v)
return _u
}
// SetNillableError sets the "error" field if the given value is not nil.
func (_u *RevisionUpdate) SetNillableError(v *string) *RevisionUpdate {
if v != nil {
_u.SetError(*v)
}
return _u
}
// ClearError clears the value of the "error" field.
func (_u *RevisionUpdate) ClearError() *RevisionUpdate {
_u.mutation.ClearError()
return _u
}
// SetErrorStmt sets the "error_stmt" field.
func (_u *RevisionUpdate) SetErrorStmt(v string) *RevisionUpdate {
_u.mutation.SetErrorStmt(v)
return _u
}
// SetNillableErrorStmt sets the "error_stmt" field if the given value is not nil.
func (_u *RevisionUpdate) SetNillableErrorStmt(v *string) *RevisionUpdate {
if v != nil {
_u.SetErrorStmt(*v)
}
return _u
}
// ClearErrorStmt clears the value of the "error_stmt" field.
func (_u *RevisionUpdate) ClearErrorStmt() *RevisionUpdate {
_u.mutation.ClearErrorStmt()
return _u
}
// SetHash sets the "hash" field.
func (_u *RevisionUpdate) SetHash(v string) *RevisionUpdate {
_u.mutation.SetHash(v)
return _u
}
// SetNillableHash sets the "hash" field if the given value is not nil.
func (_u *RevisionUpdate) SetNillableHash(v *string) *RevisionUpdate {
if v != nil {
_u.SetHash(*v)
}
return _u
}
// SetPartialHashes sets the "partial_hashes" field.
func (_u *RevisionUpdate) SetPartialHashes(v []string) *RevisionUpdate {
_u.mutation.SetPartialHashes(v)
return _u
}
// AppendPartialHashes appends value to the "partial_hashes" field.
func (_u *RevisionUpdate) AppendPartialHashes(v []string) *RevisionUpdate {
_u.mutation.AppendPartialHashes(v)
return _u
}
// ClearPartialHashes clears the value of the "partial_hashes" field.
func (_u *RevisionUpdate) ClearPartialHashes() *RevisionUpdate {
_u.mutation.ClearPartialHashes()
return _u
}
// SetOperatorVersion sets the "operator_version" field.
func (_u *RevisionUpdate) SetOperatorVersion(v string) *RevisionUpdate {
_u.mutation.SetOperatorVersion(v)
return _u
}
// SetNillableOperatorVersion sets the "operator_version" field if the given value is not nil.
func (_u *RevisionUpdate) SetNillableOperatorVersion(v *string) *RevisionUpdate {
if v != nil {
_u.SetOperatorVersion(*v)
}
return _u
}
// Mutation returns the RevisionMutation object of the builder.
func (_u *RevisionUpdate) Mutation() *RevisionMutation {
return _u.mutation
}
// Save executes the query and returns the number of nodes affected by the update operation.
func (_u *RevisionUpdate) Save(ctx context.Context) (int, error) {
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (_u *RevisionUpdate) SaveX(ctx context.Context) int {
affected, err := _u.Save(ctx)
if err != nil {
panic(err)
}
return affected
}
// Exec executes the query.
func (_u *RevisionUpdate) Exec(ctx context.Context) error {
_, err := _u.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_u *RevisionUpdate) ExecX(ctx context.Context) {
if err := _u.Exec(ctx); err != nil {
panic(err)
}
}
// check runs all checks and user-defined validators on the builder.
func (_u *RevisionUpdate) check() error {
if v, ok := _u.mutation.Applied(); ok {
if err := revision.AppliedValidator(v); err != nil {
return &ValidationError{Name: "applied", err: fmt.Errorf(`ent: validator failed for field "Revision.applied": %w`, err)}
}
}
if v, ok := _u.mutation.Total(); ok {
if err := revision.TotalValidator(v); err != nil {
return &ValidationError{Name: "total", err: fmt.Errorf(`ent: validator failed for field "Revision.total": %w`, err)}
}
}
return nil
}
func (_u *RevisionUpdate) sqlSave(ctx context.Context) (_node int, err error) {
if err := _u.check(); err != nil {
return _node, err
}
_spec := sqlgraph.NewUpdateSpec(revision.Table, revision.Columns, sqlgraph.NewFieldSpec(revision.FieldID, field.TypeString))
if ps := _u.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := _u.mutation.GetType(); ok {
_spec.SetField(revision.FieldType, field.TypeUint, value)
}
if value, ok := _u.mutation.AddedType(); ok {
_spec.AddField(revision.FieldType, field.TypeUint, value)
}
if value, ok := _u.mutation.Applied(); ok {
_spec.SetField(revision.FieldApplied, field.TypeInt, value)
}
if value, ok := _u.mutation.AddedApplied(); ok {
_spec.AddField(revision.FieldApplied, field.TypeInt, value)
}
if value, ok := _u.mutation.Total(); ok {
_spec.SetField(revision.FieldTotal, field.TypeInt, value)
}
if value, ok := _u.mutation.AddedTotal(); ok {
_spec.AddField(revision.FieldTotal, field.TypeInt, value)
}
if value, ok := _u.mutation.ExecutionTime(); ok {
_spec.SetField(revision.FieldExecutionTime, field.TypeInt64, value)
}
if value, ok := _u.mutation.AddedExecutionTime(); ok {
_spec.AddField(revision.FieldExecutionTime, field.TypeInt64, value)
}
if value, ok := _u.mutation.Error(); ok {
_spec.SetField(revision.FieldError, field.TypeString, value)
}
if _u.mutation.ErrorCleared() {
_spec.ClearField(revision.FieldError, field.TypeString)
}
if value, ok := _u.mutation.ErrorStmt(); ok {
_spec.SetField(revision.FieldErrorStmt, field.TypeString, value)
}
if _u.mutation.ErrorStmtCleared() {
_spec.ClearField(revision.FieldErrorStmt, field.TypeString)
}
if value, ok := _u.mutation.Hash(); ok {
_spec.SetField(revision.FieldHash, field.TypeString, value)
}
if value, ok := _u.mutation.PartialHashes(); ok {
_spec.SetField(revision.FieldPartialHashes, field.TypeJSON, value)
}
if value, ok := _u.mutation.AppendedPartialHashes(); ok {
_spec.AddModifier(func(u *sql.UpdateBuilder) {
sqljson.Append(u, revision.FieldPartialHashes, value)
})
}
if _u.mutation.PartialHashesCleared() {
_spec.ClearField(revision.FieldPartialHashes, field.TypeJSON)
}
if value, ok := _u.mutation.OperatorVersion(); ok {
_spec.SetField(revision.FieldOperatorVersion, field.TypeString, value)
}
_spec.Node.Schema = _u.schemaConfig.Revision
ctx = internal.NewSchemaConfigContext(ctx, _u.schemaConfig)
if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{revision.Label}
} else if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
return 0, err
}
_u.mutation.done = true
return _node, nil
}
// RevisionUpdateOne is the builder for updating a single Revision entity.
type RevisionUpdateOne struct {
config
fields []string
hooks []Hook
mutation *RevisionMutation
}
// SetType sets the "type" field.
func (_u *RevisionUpdateOne) SetType(v migrate.RevisionType) *RevisionUpdateOne {
_u.mutation.ResetType()
_u.mutation.SetType(v)
return _u
}
// SetNillableType sets the "type" field if the given value is not nil.
func (_u *RevisionUpdateOne) SetNillableType(v *migrate.RevisionType) *RevisionUpdateOne {
if v != nil {
_u.SetType(*v)
}
return _u
}
// AddType adds value to the "type" field.
func (_u *RevisionUpdateOne) AddType(v migrate.RevisionType) *RevisionUpdateOne {
_u.mutation.AddType(v)
return _u
}
// SetApplied sets the "applied" field.
func (_u *RevisionUpdateOne) SetApplied(v int) *RevisionUpdateOne {
_u.mutation.ResetApplied()
_u.mutation.SetApplied(v)
return _u
}
// SetNillableApplied sets the "applied" field if the given value is not nil.
func (_u *RevisionUpdateOne) SetNillableApplied(v *int) *RevisionUpdateOne {
if v != nil {
_u.SetApplied(*v)
}
return _u
}
// AddApplied adds value to the "applied" field.
func (_u *RevisionUpdateOne) AddApplied(v int) *RevisionUpdateOne {
_u.mutation.AddApplied(v)
return _u
}
// SetTotal sets the "total" field.
func (_u *RevisionUpdateOne) SetTotal(v int) *RevisionUpdateOne {
_u.mutation.ResetTotal()
_u.mutation.SetTotal(v)
return _u
}
// SetNillableTotal sets the "total" field if the given value is not nil.
func (_u *RevisionUpdateOne) SetNillableTotal(v *int) *RevisionUpdateOne {
if v != nil {
_u.SetTotal(*v)
}
return _u
}
// AddTotal adds value to the "total" field.
func (_u *RevisionUpdateOne) AddTotal(v int) *RevisionUpdateOne {
_u.mutation.AddTotal(v)
return _u
}
// SetExecutionTime sets the "execution_time" field.
func (_u *RevisionUpdateOne) SetExecutionTime(v time.Duration) *RevisionUpdateOne {
_u.mutation.ResetExecutionTime()
_u.mutation.SetExecutionTime(v)
return _u
}
// SetNillableExecutionTime sets the "execution_time" field if the given value is not nil.
func (_u *RevisionUpdateOne) SetNillableExecutionTime(v *time.Duration) *RevisionUpdateOne {
if v != nil {
_u.SetExecutionTime(*v)
}
return _u
}
// AddExecutionTime adds value to the "execution_time" field.
func (_u *RevisionUpdateOne) AddExecutionTime(v time.Duration) *RevisionUpdateOne {
_u.mutation.AddExecutionTime(v)
return _u
}
// SetError sets the "error" field.
func (_u *RevisionUpdateOne) SetError(v string) *RevisionUpdateOne {
_u.mutation.SetError(v)
return _u
}
// SetNillableError sets the "error" field if the given value is not nil.
func (_u *RevisionUpdateOne) SetNillableError(v *string) *RevisionUpdateOne {
if v != nil {
_u.SetError(*v)
}
return _u
}
// ClearError clears the value of the "error" field.
func (_u *RevisionUpdateOne) ClearError() *RevisionUpdateOne {
_u.mutation.ClearError()
return _u
}
// SetErrorStmt sets the "error_stmt" field.
func (_u *RevisionUpdateOne) SetErrorStmt(v string) *RevisionUpdateOne {
_u.mutation.SetErrorStmt(v)
return _u
}
// SetNillableErrorStmt sets the "error_stmt" field if the given value is not nil.
func (_u *RevisionUpdateOne) SetNillableErrorStmt(v *string) *RevisionUpdateOne {
if v != nil {
_u.SetErrorStmt(*v)
}
return _u
}
// ClearErrorStmt clears the value of the "error_stmt" field.
func (_u *RevisionUpdateOne) ClearErrorStmt() *RevisionUpdateOne {
_u.mutation.ClearErrorStmt()
return _u
}
// SetHash sets the "hash" field.
func (_u *RevisionUpdateOne) SetHash(v string) *RevisionUpdateOne {
_u.mutation.SetHash(v)
return _u
}
// SetNillableHash sets the "hash" field if the given value is not nil.
func (_u *RevisionUpdateOne) SetNillableHash(v *string) *RevisionUpdateOne {
if v != nil {
_u.SetHash(*v)
}
return _u
}
// SetPartialHashes sets the "partial_hashes" field.
func (_u *RevisionUpdateOne) SetPartialHashes(v []string) *RevisionUpdateOne {
_u.mutation.SetPartialHashes(v)
return _u
}
// AppendPartialHashes appends value to the "partial_hashes" field.
func (_u *RevisionUpdateOne) AppendPartialHashes(v []string) *RevisionUpdateOne {
_u.mutation.AppendPartialHashes(v)
return _u
}
// ClearPartialHashes clears the value of the "partial_hashes" field.
func (_u *RevisionUpdateOne) ClearPartialHashes() *RevisionUpdateOne {
_u.mutation.ClearPartialHashes()
return _u
}
// SetOperatorVersion sets the "operator_version" field.
func (_u *RevisionUpdateOne) SetOperatorVersion(v string) *RevisionUpdateOne {
_u.mutation.SetOperatorVersion(v)
return _u
}
// SetNillableOperatorVersion sets the "operator_version" field if the given value is not nil.
func (_u *RevisionUpdateOne) SetNillableOperatorVersion(v *string) *RevisionUpdateOne {
if v != nil {
_u.SetOperatorVersion(*v)
}
return _u
}
// Mutation returns the RevisionMutation object of the builder.
func (_u *RevisionUpdateOne) Mutation() *RevisionMutation {
return _u.mutation
}
// Where appends a list predicates to the RevisionUpdate builder.
func (_u *RevisionUpdateOne) Where(ps ...predicate.Revision) *RevisionUpdateOne {
_u.mutation.Where(ps...)
return _u
}
// Select allows selecting one or more fields (columns) of the returned entity.
// The default is selecting all fields defined in the entity schema.
func (_u *RevisionUpdateOne) Select(field string, fields ...string) *RevisionUpdateOne {
_u.fields = append([]string{field}, fields...)
return _u
}
// Save executes the query and returns the updated Revision entity.
func (_u *RevisionUpdateOne) Save(ctx context.Context) (*Revision, error) {
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (_u *RevisionUpdateOne) SaveX(ctx context.Context) *Revision {
node, err := _u.Save(ctx)
if err != nil {
panic(err)
}
return node
}
// Exec executes the query on the entity.
func (_u *RevisionUpdateOne) Exec(ctx context.Context) error {
_, err := _u.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_u *RevisionUpdateOne) ExecX(ctx context.Context) {
if err := _u.Exec(ctx); err != nil {
panic(err)
}
}
// check runs all checks and user-defined validators on the builder.
func (_u *RevisionUpdateOne) check() error {
if v, ok := _u.mutation.Applied(); ok {
if err := revision.AppliedValidator(v); err != nil {
return &ValidationError{Name: "applied", err: fmt.Errorf(`ent: validator failed for field "Revision.applied": %w`, err)}
}
}
if v, ok := _u.mutation.Total(); ok {
if err := revision.TotalValidator(v); err != nil {
return &ValidationError{Name: "total", err: fmt.Errorf(`ent: validator failed for field "Revision.total": %w`, err)}
}
}
return nil
}
func (_u *RevisionUpdateOne) sqlSave(ctx context.Context) (_node *Revision, err error) {
if err := _u.check(); err != nil {
return _node, err
}
_spec := sqlgraph.NewUpdateSpec(revision.Table, revision.Columns, sqlgraph.NewFieldSpec(revision.FieldID, field.TypeString))
id, ok := _u.mutation.ID()
if !ok {
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Revision.id" for update`)}
}
_spec.Node.ID.Value = id
if fields := _u.fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, revision.FieldID)
for _, f := range fields {
if !revision.ValidColumn(f) {
return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
if f != revision.FieldID {
_spec.Node.Columns = append(_spec.Node.Columns, f)
}
}
}
if ps := _u.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := _u.mutation.GetType(); ok {
_spec.SetField(revision.FieldType, field.TypeUint, value)
}
if value, ok := _u.mutation.AddedType(); ok {
_spec.AddField(revision.FieldType, field.TypeUint, value)
}
if value, ok := _u.mutation.Applied(); ok {
_spec.SetField(revision.FieldApplied, field.TypeInt, value)
}
if value, ok := _u.mutation.AddedApplied(); ok {
_spec.AddField(revision.FieldApplied, field.TypeInt, value)
}
if value, ok := _u.mutation.Total(); ok {
_spec.SetField(revision.FieldTotal, field.TypeInt, value)
}
if value, ok := _u.mutation.AddedTotal(); ok {
_spec.AddField(revision.FieldTotal, field.TypeInt, value)
}
if value, ok := _u.mutation.ExecutionTime(); ok {
_spec.SetField(revision.FieldExecutionTime, field.TypeInt64, value)
}
if value, ok := _u.mutation.AddedExecutionTime(); ok {
_spec.AddField(revision.FieldExecutionTime, field.TypeInt64, value)
}
if value, ok := _u.mutation.Error(); ok {
_spec.SetField(revision.FieldError, field.TypeString, value)
}
if _u.mutation.ErrorCleared() {
_spec.ClearField(revision.FieldError, field.TypeString)
}
if value, ok := _u.mutation.ErrorStmt(); ok {
_spec.SetField(revision.FieldErrorStmt, field.TypeString, value)
}
if _u.mutation.ErrorStmtCleared() {
_spec.ClearField(revision.FieldErrorStmt, field.TypeString)
}
if value, ok := _u.mutation.Hash(); ok {
_spec.SetField(revision.FieldHash, field.TypeString, value)
}
if value, ok := _u.mutation.PartialHashes(); ok {
_spec.SetField(revision.FieldPartialHashes, field.TypeJSON, value)
}
if value, ok := _u.mutation.AppendedPartialHashes(); ok {
_spec.AddModifier(func(u *sql.UpdateBuilder) {
sqljson.Append(u, revision.FieldPartialHashes, value)
})
}
if _u.mutation.PartialHashesCleared() {
_spec.ClearField(revision.FieldPartialHashes, field.TypeJSON)
}
if value, ok := _u.mutation.OperatorVersion(); ok {
_spec.SetField(revision.FieldOperatorVersion, field.TypeString, value)
}
_spec.Node.Schema = _u.schemaConfig.Revision
ctx = internal.NewSchemaConfigContext(ctx, _u.schemaConfig)
_node = &Revision{config: _u.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues
if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{revision.Label}
} else if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
return nil, err
}
_u.mutation.done = true
return _node, nil
}
================================================
FILE: cmd/atlas/internal/migrate/ent/runtime/runtime.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package runtime
// The schema-stitching logic is generated in ariga.io/atlas/cmd/atlas/internal/migrate/ent/runtime.go
const (
Version = "v0.14.5-0.20250523082027-21ecfa0872d4" // Version of ent codegen.
Sum = "h1:d7UZAvQCnOp1PyiHAWkPCXBEPW3tVjraiK/RZlsW0XY=" // Sum of ent codegen.
)
================================================
FILE: cmd/atlas/internal/migrate/ent/runtime.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package ent
import (
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/schema"
"ariga.io/atlas/sql/migrate"
)
// The init function reads all schema descriptors with runtime code
// (default values, validators, hooks and policies) and stitches it
// to their package variables.
func init() {
revisionFields := schema.Revision{}.Fields()
_ = revisionFields
// revisionDescType is the schema descriptor for type field.
revisionDescType := revisionFields[2].Descriptor()
// revision.DefaultType holds the default value on creation for the type field.
revision.DefaultType = migrate.RevisionType(revisionDescType.Default.(uint))
// revisionDescApplied is the schema descriptor for applied field.
revisionDescApplied := revisionFields[3].Descriptor()
// revision.DefaultApplied holds the default value on creation for the applied field.
revision.DefaultApplied = revisionDescApplied.Default.(int)
// revision.AppliedValidator is a validator for the "applied" field. It is called by the builders before save.
revision.AppliedValidator = revisionDescApplied.Validators[0].(func(int) error)
// revisionDescTotal is the schema descriptor for total field.
revisionDescTotal := revisionFields[4].Descriptor()
// revision.DefaultTotal holds the default value on creation for the total field.
revision.DefaultTotal = revisionDescTotal.Default.(int)
// revision.TotalValidator is a validator for the "total" field. It is called by the builders before save.
revision.TotalValidator = revisionDescTotal.Validators[0].(func(int) error)
}
================================================
FILE: cmd/atlas/internal/migrate/ent/schema/revision.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package schema
import (
"time"
"ariga.io/atlas/sql/migrate"
"entgo.io/ent"
"entgo.io/ent/dialect/entsql"
"entgo.io/ent/schema"
"entgo.io/ent/schema/field"
)
// DefaultRevisionSchema is the default schema for storing revisions table.
const DefaultRevisionSchema = "atlas_schema_revisions"
// Revision holds the schema definition for the Revision entity.
type Revision struct {
ent.Schema
}
// Fields of the Revision.
func (Revision) Fields() []ent.Field {
return []ent.Field{
field.String("id").
StorageKey("version").
Immutable(),
field.String("description").
Immutable(),
field.Uint("type").
GoType(migrate.RevisionType(0)).
Default(uint(migrate.RevisionTypeExecute)),
field.Int("applied").
NonNegative().
Default(0),
field.Int("total").
NonNegative().
Default(0),
field.Time("executed_at").
Immutable(),
field.Int64("execution_time").
GoType(time.Duration(0)),
field.Text("error").
Optional(),
field.Text("error_stmt").
Optional(),
field.String("hash"),
field.Strings("partial_hashes").
Optional(),
field.String("operator_version"),
}
}
// Annotations of the Revision.
func (Revision) Annotations() []schema.Annotation {
return []schema.Annotation{
entsql.Annotation{Table: DefaultRevisionSchema},
}
}
================================================
FILE: cmd/atlas/internal/migrate/ent/template/convert.tmpl
================================================
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
{{ define "convert" }}
{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}
import "ariga.io/atlas/sql/migrate"
{{ range $n := $.Nodes }}
{{ if eq $n.Name "Revision" }}
{{ $builder := $n.CreateName }}
{{ $receiver := receiver $builder }}
// SetRevision takes the values for each field from the given migrate.Revision.
func ({{ $receiver }} *{{ $builder }}) SetRevision(rev *migrate.Revision) *{{ $builder }} {
{{ $receiver }}.SetID(rev.Version)
{{- range $f := $n.Fields }}
{{ $receiver }}.Set{{ $f.StructField }}(rev.{{ $f.StructField }})
{{- end }}
return {{ $receiver }}
}
// AtlasRevision returns an migrate.Revision from the current Revision.
func({{ $n.Receiver }} *Revision) AtlasRevision() *migrate.Revision {
return &migrate.Revision{
Version: {{ $n.Receiver }}.ID,
{{- range $f := $n.Fields }}
{{ $f.StructField }}: {{ $n.Receiver }}.{{ $f.StructField }},
{{- end }}
}
}
{{ end }}
{{ end }}
{{ end }}
================================================
FILE: cmd/atlas/internal/migrate/ent/tx.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Code generated by entc, DO NOT EDIT.
package ent
import (
"context"
stdsql "database/sql"
"fmt"
"sync"
"entgo.io/ent/dialect"
)
// Tx is a transactional client that is created by calling Client.Tx().
type Tx struct {
config
// Revision is the client for interacting with the Revision builders.
Revision *RevisionClient
// lazily loaded.
client *Client
clientOnce sync.Once
// ctx lives for the life of the transaction. It is
// the same context used by the underlying connection.
ctx context.Context
}
type (
// Committer is the interface that wraps the Commit method.
Committer interface {
Commit(context.Context, *Tx) error
}
// The CommitFunc type is an adapter to allow the use of ordinary
// function as a Committer. If f is a function with the appropriate
// signature, CommitFunc(f) is a Committer that calls f.
CommitFunc func(context.Context, *Tx) error
// CommitHook defines the "commit middleware". A function that gets a Committer
// and returns a Committer. For example:
//
// hook := func(next ent.Committer) ent.Committer {
// return ent.CommitFunc(func(ctx context.Context, tx *ent.Tx) error {
// // Do some stuff before.
// if err := next.Commit(ctx, tx); err != nil {
// return err
// }
// // Do some stuff after.
// return nil
// })
// }
//
CommitHook func(Committer) Committer
)
// Commit calls f(ctx, m).
func (f CommitFunc) Commit(ctx context.Context, tx *Tx) error {
return f(ctx, tx)
}
// Commit commits the transaction.
func (tx *Tx) Commit() error {
txDriver := tx.config.driver.(*txDriver)
var fn Committer = CommitFunc(func(context.Context, *Tx) error {
return txDriver.tx.Commit()
})
txDriver.mu.Lock()
hooks := append([]CommitHook(nil), txDriver.onCommit...)
txDriver.mu.Unlock()
for i := len(hooks) - 1; i >= 0; i-- {
fn = hooks[i](fn)
}
return fn.Commit(tx.ctx, tx)
}
// OnCommit adds a hook to call on commit.
func (tx *Tx) OnCommit(f CommitHook) {
txDriver := tx.config.driver.(*txDriver)
txDriver.mu.Lock()
txDriver.onCommit = append(txDriver.onCommit, f)
txDriver.mu.Unlock()
}
type (
// Rollbacker is the interface that wraps the Rollback method.
Rollbacker interface {
Rollback(context.Context, *Tx) error
}
// The RollbackFunc type is an adapter to allow the use of ordinary
// function as a Rollbacker. If f is a function with the appropriate
// signature, RollbackFunc(f) is a Rollbacker that calls f.
RollbackFunc func(context.Context, *Tx) error
// RollbackHook defines the "rollback middleware". A function that gets a Rollbacker
// and returns a Rollbacker. For example:
//
// hook := func(next ent.Rollbacker) ent.Rollbacker {
// return ent.RollbackFunc(func(ctx context.Context, tx *ent.Tx) error {
// // Do some stuff before.
// if err := next.Rollback(ctx, tx); err != nil {
// return err
// }
// // Do some stuff after.
// return nil
// })
// }
//
RollbackHook func(Rollbacker) Rollbacker
)
// Rollback calls f(ctx, m).
func (f RollbackFunc) Rollback(ctx context.Context, tx *Tx) error {
return f(ctx, tx)
}
// Rollback rollbacks the transaction.
func (tx *Tx) Rollback() error {
txDriver := tx.config.driver.(*txDriver)
var fn Rollbacker = RollbackFunc(func(context.Context, *Tx) error {
return txDriver.tx.Rollback()
})
txDriver.mu.Lock()
hooks := append([]RollbackHook(nil), txDriver.onRollback...)
txDriver.mu.Unlock()
for i := len(hooks) - 1; i >= 0; i-- {
fn = hooks[i](fn)
}
return fn.Rollback(tx.ctx, tx)
}
// OnRollback adds a hook to call on rollback.
func (tx *Tx) OnRollback(f RollbackHook) {
txDriver := tx.config.driver.(*txDriver)
txDriver.mu.Lock()
txDriver.onRollback = append(txDriver.onRollback, f)
txDriver.mu.Unlock()
}
// Client returns a Client that binds to current transaction.
func (tx *Tx) Client() *Client {
tx.clientOnce.Do(func() {
tx.client = &Client{config: tx.config}
tx.client.init()
})
return tx.client
}
func (tx *Tx) init() {
tx.Revision = NewRevisionClient(tx.config)
}
// txDriver wraps the given dialect.Tx with a nop dialect.Driver implementation.
// The idea is to support transactions without adding any extra code to the builders.
// When a builder calls to driver.Tx(), it gets the same dialect.Tx instance.
// Commit and Rollback are nop for the internal builders and the user must call one
// of them in order to commit or rollback the transaction.
//
// If a closed transaction is embedded in one of the generated entities, and the entity
// applies a query, for example: Revision.QueryXXX(), the query will be executed
// through the driver which created this transaction.
//
// Note that txDriver is not goroutine safe.
type txDriver struct {
// the driver we started the transaction from.
drv dialect.Driver
// tx is the underlying transaction.
tx dialect.Tx
// completion hooks.
mu sync.Mutex
onCommit []CommitHook
onRollback []RollbackHook
}
// newTx creates a new transactional driver.
func newTx(ctx context.Context, drv dialect.Driver) (*txDriver, error) {
tx, err := drv.Tx(ctx)
if err != nil {
return nil, err
}
return &txDriver{tx: tx, drv: drv}, nil
}
// Tx returns the transaction wrapper (txDriver) to avoid Commit or Rollback calls
// from the internal builders. Should be called only by the internal builders.
func (tx *txDriver) Tx(context.Context) (dialect.Tx, error) { return tx, nil }
// Dialect returns the dialect of the driver we started the transaction from.
func (tx *txDriver) Dialect() string { return tx.drv.Dialect() }
// Close is a nop close.
func (*txDriver) Close() error { return nil }
// Commit is a nop commit for the internal builders.
// User must call `Tx.Commit` in order to commit the transaction.
func (*txDriver) Commit() error { return nil }
// Rollback is a nop rollback for the internal builders.
// User must call `Tx.Rollback` in order to rollback the transaction.
func (*txDriver) Rollback() error { return nil }
// Exec calls tx.Exec.
func (tx *txDriver) Exec(ctx context.Context, query string, args, v any) error {
return tx.tx.Exec(ctx, query, args, v)
}
// Query calls tx.Query.
func (tx *txDriver) Query(ctx context.Context, query string, args, v any) error {
return tx.tx.Query(ctx, query, args, v)
}
var _ dialect.Driver = (*txDriver)(nil)
// ExecContext allows calling the underlying ExecContext method of the transaction if it is supported by it.
// See, database/sql#Tx.ExecContext for more information.
func (tx *txDriver) ExecContext(ctx context.Context, query string, args ...any) (stdsql.Result, error) {
ex, ok := tx.tx.(interface {
ExecContext(context.Context, string, ...any) (stdsql.Result, error)
})
if !ok {
return nil, fmt.Errorf("Tx.ExecContext is not supported")
}
return ex.ExecContext(ctx, query, args...)
}
// QueryContext allows calling the underlying QueryContext method of the transaction if it is supported by it.
// See, database/sql#Tx.QueryContext for more information.
func (tx *txDriver) QueryContext(ctx context.Context, query string, args ...any) (*stdsql.Rows, error) {
q, ok := tx.tx.(interface {
QueryContext(context.Context, string, ...any) (*stdsql.Rows, error)
})
if !ok {
return nil, fmt.Errorf("Tx.QueryContext is not supported")
}
return q.QueryContext(ctx, query, args...)
}
================================================
FILE: cmd/atlas/internal/migrate/migrate.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package migrate
import (
"context"
"errors"
"fmt"
"io/fs"
"net/url"
"os"
"path"
"path/filepath"
"slices"
"strings"
"time"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/mysql"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
"ariga.io/atlas/sql/sqlite"
"ariga.io/atlas/sql/sqltool"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql"
entschema "entgo.io/ent/dialect/sql/schema"
"github.com/google/uuid"
)
type (
// RevisionReadWriter is a revision read-writer with migration capabilities.
RevisionReadWriter interface {
migrate.RevisionReadWriter
// CurrentRevision returns the current revision in the revisions table.
CurrentRevision(context.Context) (*migrate.Revision, error)
// Migrate applies the migration of the revisions table.
Migrate(context.Context) error
// ID returns the current target identifier.
ID(context.Context, string) (string, error)
}
// EntRevisions provides implementation for the migrate.RevisionReadWriter interface.
EntRevisions struct {
ac *sqlclient.Client // underlying Atlas client
ec *ent.Client // underlying Ent client
schema string // name of the schema the revision table resides in
}
// Option allows to configure EntRevisions by using functional arguments.
Option func(*EntRevisions) error
)
// Dialect returns the "ent dialect" of the Ent client.
func (r *EntRevisions) Dialect() string {
return EntDialect(r.ac.Name)
}
// EntDialect returns the Ent dialect for the given driver.
func EntDialect(d string) string {
switch {
case d == mysql.DriverMaria:
return dialect.MySQL // Ent does not support "mariadb" as dialect.
case strings.HasPrefix(d, "libsql"):
return dialect.SQLite // Ent does not support "libsql" as dialect.
case d == sqlite.DriverName:
return dialect.SQLite // Ent does not support "sqlite" as dialect.
default:
return d
}
}
// RevisionsForClient creates a new RevisionReadWriter for the given sqlclient.Client.
func RevisionsForClient(ctx context.Context, ac *sqlclient.Client, schema string) (RevisionReadWriter, error) {
// If the driver supports the RevisionReadWriter interface, use it.
if drv, ok := ac.Driver.(interface {
RevisionsReadWriter(context.Context, string) (migrate.RevisionReadWriter, error)
}); ok {
rrw, err := drv.RevisionsReadWriter(ctx, schema)
if err != nil {
return nil, err
}
if rrw, ok := rrw.(RevisionReadWriter); ok {
return rrw, nil
}
return nil, fmt.Errorf("unexpected revision read-writer type: %T", rrw)
}
return NewEntRevisions(ctx, ac, WithSchema(schema))
}
// NewEntRevisions creates a new EntRevisions with the given sqlclient.Client.
func NewEntRevisions(ctx context.Context, ac *sqlclient.Client, opts ...Option) (*EntRevisions, error) {
r := &EntRevisions{ac: ac}
for _, opt := range opts {
if err := opt(r); err != nil {
return nil, err
}
}
if r.Dialect() == dialect.SQLite && r.schema != "" && r.schema != "main" {
return nil, fmt.Errorf("cannot store revisions-table in a separate schema (%q) with SQLite driver", r.schema)
}
// Create the connection with the underlying migrate.Driver to have it inside a possible transaction.
entopts := []ent.Option{ent.Driver(sql.NewDriver(r.Dialect(), sql.Conn{ExecQuerier: r.ac.Driver}))}
// SQLite does not support multiple schema, therefore schema-config is only needed for other dialects.
if r.Dialect() != dialect.SQLite {
// Make sure the schema to store the revisions table in does exist.
_, err := r.ac.InspectSchema(ctx, r.schema, &schema.InspectOptions{Mode: schema.InspectSchemas})
if err != nil && !schema.IsNotExistError(err) {
return nil, err
}
if schema.IsNotExistError(err) {
if err := r.ac.ApplyChanges(ctx, []schema.Change{
&schema.AddSchema{S: &schema.Schema{Name: r.schema}},
}); err != nil {
return nil, err
}
}
// Tell Ent to operate on a given schema.
if r.schema != "" {
entopts = append(entopts, ent.AlternateSchema(ent.SchemaConfig{Revision: r.schema}))
}
}
// Instantiate the Ent client and migrate the revision schema.
r.ec = ent.NewClient(entopts...)
return r, nil
}
// WithSchema configures the schema to use for the revision table.
func WithSchema(s string) Option {
return func(r *EntRevisions) error {
r.schema = s
return nil
}
}
// Ident returns the table identifier.
func (r *EntRevisions) Ident() *migrate.TableIdent {
return &migrate.TableIdent{Name: revision.Table, Schema: r.schema}
}
// ReadRevision reads a revision from the revisions table.
//
// ReadRevision will not return results only saved in cache.
func (r *EntRevisions) ReadRevision(ctx context.Context, v string) (*migrate.Revision, error) {
if v == revisionID {
return nil, errors.New("cannot read revision-table identifier as revision")
}
rev, err := r.ec.Revision.Get(ctx, v)
if err != nil && !ent.IsNotFound(err) {
return nil, err
}
if ent.IsNotFound(err) {
return nil, migrate.ErrRevisionNotExist
}
return rev.AtlasRevision(), nil
}
// ReadRevisions reads the revisions from the revisions table.
//
// ReadRevisions will not return results only saved to cache.
func (r *EntRevisions) ReadRevisions(ctx context.Context) ([]*migrate.Revision, error) {
revs, err := r.ec.Revision.Query().
Where(revision.IDNEQ(revisionID)).
Order(revision.ByID()).
All(ctx)
if err != nil {
return nil, err
}
ret := make([]*migrate.Revision, len(revs))
for i, rev := range revs {
ret[i] = rev.AtlasRevision()
}
return ret, nil
}
// CurrentRevision returns the current (latest) revision in the revisions table.
func (r *EntRevisions) CurrentRevision(ctx context.Context) (*migrate.Revision, error) {
rev, err := r.ec.Revision.Query().
Where(revision.IDNEQ(revisionID)).
Order(revision.ByID(sql.OrderDesc())).
First(ctx)
if err != nil && !ent.IsNotFound(err) {
return nil, err
}
if ent.IsNotFound(err) {
return nil, migrate.ErrRevisionNotExist
}
return rev.AtlasRevision(), nil
}
// WriteRevision writes a revision to the revisions table.
func (r *EntRevisions) WriteRevision(ctx context.Context, rev *migrate.Revision) error {
if rev.Version == revisionID {
return errors.New("writing the revision-table identifier is not allowed")
}
return r.ec.Revision.Create().
SetRevision(rev).
OnConflict(sql.ConflictColumns(revision.FieldID)).
UpdateNewValues().
Exec(ctx)
}
// DeleteRevision deletes a revision from the revisions table.
func (r *EntRevisions) DeleteRevision(ctx context.Context, v string) error {
if v == revisionID {
return errors.New("deleting the revision-table identifier is not allowed")
}
return r.ec.Revision.DeleteOneID(v).Exec(ctx)
}
// Migrate attempts to create / update the revisions table. This is separated since Ent attempts to wrap the migration
// execution in a transaction and assumes the underlying connection is of type *sql.DB, which is not true for actually
// reading and writing revisions.
func (r *EntRevisions) Migrate(ctx context.Context) (err error) {
var (
opts = []entschema.MigrateOption{
entschema.WithDropColumn(true),
}
c = ent.NewClient(ent.Driver(sql.OpenDB(r.Dialect(), r.ac.DB)))
)
switch {
case r.Dialect() != dialect.SQLite:
// Ensure the ent client is bound to the requested revision schema. Open a new connection, if not.
if r.ac.URL.Schema != r.schema {
sc, err := sqlclient.OpenURL(ctx, r.ac.URL.URL, sqlclient.OpenSchema(r.schema))
if err != nil {
return err
}
defer sc.Close()
c = ent.NewClient(ent.Driver(sql.OpenDB(r.Dialect(), sc.DB)))
}
// In non-SQLite databases, there can be multiple schemas, and we
// prefer to pass it explicitly rather than calling to CURRENT_SCHEMA().
opts = append(opts, entschema.WithSchemaName(r.schema))
default: // SQLite.
var on sql.NullBool
if err := r.ac.DB.QueryRowContext(ctx, "PRAGMA foreign_keys").Scan(&on); err != nil {
return err
}
if !on.Bool {
// Ent requires the foreign key checks in SQLite to be enabled for migration. Since Atlas does not,
// ensure they are set for the migration attempt and restore previous setting afterwards.
_, err := r.ac.ExecContext(ctx, "PRAGMA foreign_keys = on")
if err != nil {
return err
}
defer func() {
_, err2 := r.ac.ExecContext(ctx, "PRAGMA foreign_keys = off")
if err2 != nil {
if err != nil {
err = fmt.Errorf("%v: %w", err2, err)
return
}
err = err2
}
}()
}
}
return c.Schema.Create(ctx, append(opts, entschema.WithDiffHook(func(next entschema.Differ) entschema.Differ {
return entschema.DiffFunc(func(current, desired *schema.Schema) ([]schema.Change, error) {
changes, err := next.Diff(current, desired)
if err != nil {
return nil, err
}
// Skip all changes beside revisions
// table creation or modification.
for i := range changes {
switch cs := changes[i].(type) {
case *schema.AddTable:
r.maySetSchemaQualifier(cs.T)
if cs.T.Name == revision.Table {
return schema.Changes{cs}, nil
}
case *schema.ModifyTable:
r.maySetSchemaQualifier(cs.T)
if cs.T.Name == revision.Table {
return schema.Changes{cs}, nil
}
}
}
return nil, nil
})
}))...)
}
// maySetSchemaQualifier sets the schema on the atlas_schema_revisions table
// for cases the migration should use qualified identifiers due to some limitation
// in PostgreSQL services that use "connection pooler" and do not support the "search_path"
// parameter. See: https://github.com/ariga/atlas/issues/2509.
func (r *EntRevisions) maySetSchemaQualifier(t *schema.Table) {
if r.Dialect() != dialect.Postgres || r.schema == "" || t.Schema != nil {
return // Not PG, or schema-scope (e.g., public).
}
if knownServices := []string{"neon.tech", "supabase.co", "supabase.com"}; slices.ContainsFunc(knownServices, func(s string) bool {
return strings.HasSuffix(r.ac.URL.Host, s)
}) {
t.SetSchema(schema.New(r.schema))
}
}
// revisionID holds the column "id" ("version") of the revision that holds the identifier of the
// connected revisions table. The "." prefix ensures the is it lower than any other revisions.
const revisionID = ".atlas_cloud_identifier"
// ID returns the identifier of the connected revisions table.
func (r *EntRevisions) ID(ctx context.Context, operatorV string) (string, error) {
err := r.ec.Revision.Create().
SetID(revisionID). // identifier key
SetDescription(uuid.NewString()). // actual revision identifier
SetOperatorVersion(operatorV). // operator version
SetExecutedAt(time.Now()). // when it was set
SetExecutionTime(0). // dummy values
SetHash("").
OnConflict(sql.ConflictColumns(revision.FieldID)).
Ignore().
Exec(ctx)
if err != nil {
return "", fmt.Errorf("upsert revision-table id: %w", err)
}
rev, err := r.ec.Revision.Get(ctx, revisionID)
if err != nil {
return "", fmt.Errorf("read revision-table id: %w", err)
}
id, err := uuid.Parse(rev.Description)
if err != nil {
return "", fmt.Errorf("parse revision-table id: %w", err)
}
return id.String(), nil
}
var _ migrate.RevisionReadWriter = (*EntRevisions)(nil)
// List of supported formats.
const (
FormatAtlas = "atlas"
FormatGolangMigrate = "golang-migrate"
FormatGoose = "goose"
FormatFlyway = "flyway"
FormatLiquibase = "liquibase"
FormatDBMate = "dbmate"
)
// Formats is the list of supported formats.
var Formats = []string{FormatAtlas, FormatGolangMigrate, FormatGoose, FormatFlyway, FormatLiquibase, FormatDBMate}
// Formatter returns the dir formatter for its URL.
func Formatter(u *url.URL) (migrate.Formatter, error) {
switch f := u.Query().Get("format"); f {
case "", FormatAtlas:
return migrate.DefaultFormatter, nil
case FormatGolangMigrate:
return sqltool.GolangMigrateFormatter, nil
case FormatGoose:
return sqltool.GooseFormatter, nil
case FormatFlyway:
return sqltool.FlywayFormatter, nil
case FormatLiquibase:
return sqltool.LiquibaseFormatter, nil
case FormatDBMate:
return sqltool.DBMateFormatter, nil
default:
return nil, fmt.Errorf("unknown format %q", f)
}
}
// Dir parses u and calls dirURL.
func Dir(ctx context.Context, u string, create bool) (migrate.Dir, error) {
parsed, err := url.Parse(u)
if err != nil {
return nil, err
}
return DirURL(ctx, parsed, create)
}
// Directory types (URL schemes).
const (
DirTypeMem = "mem"
DirTypeFile = "file"
DirTypeAtlas = "atlas"
)
// DefaultDirName is the default directory name.
const DefaultDirName = "migrations"
// DirURL returns a migrate.Dir to use as migration directory.
func DirURL(ctx context.Context, u *url.URL, create bool) (migrate.Dir, error) {
p := filepath.Join(u.Host, u.Path)
switch u.Scheme {
case DirTypeMem:
return migrate.OpenMemDir(path.Join(u.Host, u.Path)), nil
case DirTypeFile:
if p == "" {
p = DefaultDirName
}
case DirTypeAtlas:
return openAtlasDir(ctx, u)
case "":
return nil, fmt.Errorf("missing scheme for dir url. Did you mean %q? ", fmt.Sprintf("%s://%s", DirTypeFile, u.Path))
default:
return nil, fmt.Errorf("unsupported driver %q", u.Scheme)
}
fn := func() (migrate.Dir, error) { return migrate.NewLocalDir(p) }
switch f := u.Query().Get("format"); f {
case "", FormatAtlas:
// this is the default
case FormatGolangMigrate:
fn = func() (migrate.Dir, error) { return sqltool.NewGolangMigrateDir(p) }
case FormatGoose:
fn = func() (migrate.Dir, error) { return sqltool.NewGooseDir(p) }
case FormatFlyway:
fn = func() (migrate.Dir, error) { return sqltool.NewFlywayDir(p) }
case FormatLiquibase:
fn = func() (migrate.Dir, error) { return sqltool.NewLiquibaseDir(p) }
case FormatDBMate:
fn = func() (migrate.Dir, error) { return sqltool.NewDBMateDir(p) }
default:
return nil, fmt.Errorf("unknown dir format %q", f)
}
d, err := fn()
if create && errors.Is(err, fs.ErrNotExist) {
if err := os.MkdirAll(p, 0755); err != nil {
return nil, err
}
d, err = fn()
if err != nil {
return nil, err
}
}
return d, err
}
// ChangesToRealm returns the schema changes for creating the given Realm.
func ChangesToRealm(c *sqlclient.Client, r *schema.Realm) schema.Changes {
var changes schema.Changes
for _, o := range r.Objects {
changes = append(changes, &schema.AddObject{O: o})
}
for _, s := range r.Schemas {
// Generate commands for creating the schemas on realm-mode.
if c.URL.Schema == "" {
changes = append(changes, &schema.AddSchema{S: s})
}
for _, o := range s.Objects {
changes = append(changes, &schema.AddObject{O: o})
}
for _, t := range s.Tables {
changes = append(changes, &schema.AddTable{T: t})
for _, r := range t.Triggers {
changes = append(changes, &schema.AddTrigger{T: r})
}
}
for _, v := range s.Views {
changes = append(changes, &schema.AddView{V: v})
for _, r := range v.Triggers {
changes = append(changes, &schema.AddTrigger{T: r})
}
}
for _, f := range s.Funcs {
changes = append(changes, &schema.AddFunc{F: f})
}
for _, p := range s.Procs {
changes = append(changes, &schema.AddProc{P: p})
}
}
return changes
}
================================================
FILE: cmd/atlas/internal/migrate/migrate_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package migrate
import (
"context"
"fmt"
"net/url"
"ariga.io/atlas/sql/migrate"
)
func openAtlasDir(context.Context, *url.URL) (migrate.Dir, error) {
return nil, fmt.Errorf("atlas remote directory is not supported by this release. See: https://atlasgo.io/getting-started")
}
================================================
FILE: cmd/atlas/internal/migrate/migrate_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package migrate
import (
"context"
"errors"
"fmt"
"net/url"
"path/filepath"
"testing"
"time"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/sqlclient"
"ariga.io/atlas/sql/sqltool"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
)
func TestFormatter(t *testing.T) {
u, err := url.Parse("file://migrations")
require.NoError(t, err)
f, err := Formatter(u)
require.NoError(t, err)
require.Equal(t, migrate.DefaultFormatter, f)
u, err = url.Parse("file://migrations?format=atlas")
require.NoError(t, err)
f, err = Formatter(u)
u, err = url.Parse("file://migrations?format=flyway")
require.NoError(t, err)
f, err = Formatter(u)
require.NoError(t, err)
require.Equal(t, sqltool.FlywayFormatter, f)
}
func TestRevisionsForClient(t *testing.T) {
ctx := context.Background()
c, err := sqlclient.Open(ctx, "sqlite://?mode=memory")
require.NoError(t, err)
var rrw RevisionReadWriter
rrw, err = RevisionsForClient(ctx, c, "")
require.NoError(t, err)
require.NotNil(t, rrw)
_, ok := rrw.(*EntRevisions)
require.True(t, ok, "RevisionsForClient should return an EntRevisions")
drvMock := &mockDriver{Driver: c.Driver, rrw: &migrate.NopRevisionReadWriter{}}
c.Driver = drvMock
rrw, err = RevisionsForClient(ctx, c, "")
require.ErrorContains(t, err, "unexpected revision read-writer type: *migrate.NopRevisionReadWriter")
drvMock.rrw = &mockrrw{RevisionReadWriter: &migrate.NopRevisionReadWriter{}}
rrw, err = RevisionsForClient(ctx, c, "")
require.NoError(t, err)
_, ok = rrw.(*mockrrw)
require.True(t, ok, "RevisionsForClient should return a mockrrw")
}
func TestNewEntRevisions(t *testing.T) {
ctx := context.Background()
c, err := sqlclient.Open(ctx, "sqlite://?mode=memory")
require.NoError(t, err)
r, err := NewEntRevisions(ctx, c)
require.NoError(t, err)
runRevisionsTests(ctx, t, c.Driver, r)
}
func TestDirURL(t *testing.T) {
localDir := t.TempDir()
tests := []struct {
name string
url string
create bool
expected func() migrate.Dir
expectedErr error
}{
{
name: "Valid file URL",
url: "file://" + localDir,
create: false,
expected: func() migrate.Dir {
d, err := migrate.NewLocalDir(localDir)
require.NoError(t, err)
return d
},
},
{
name: "Create local dir",
url: "file://" + filepath.Join(localDir, "new/dir"),
create: true,
expected: func() migrate.Dir {
d, err := migrate.NewLocalDir(filepath.Join(localDir, "new/dir"))
require.NoError(t, err)
return d
},
},
{
name: "Dont create local dir",
url: "file://" + filepath.Join(localDir, "new/dir/2"),
create: false,
expectedErr: fmt.Errorf("sql/migrate: stat %s: no such file or directory", filepath.Join(localDir, "new/dir/2")),
},
{
name: "No scheme",
url: localDir,
create: false,
expectedErr: fmt.Errorf("missing scheme for dir url. Did you mean %q? ", "file://"+localDir),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir, err := Dir(context.Background(), tt.url, tt.create)
if tt.expectedErr != nil {
require.EqualError(t, err, tt.expectedErr.Error())
} else {
require.NoError(t, err)
require.Equal(t, tt.expected(), dir)
}
})
}
}
func runRevisionsTests(ctx context.Context, t *testing.T, drv migrate.Driver, r RevisionReadWriter) {
_, err := drv.ExecContext(ctx, "CREATE VIEW v1(c1) AS SELECT 1;")
require.NoError(t, err)
require.NoError(t, r.Migrate(ctx))
s, err := drv.InspectSchema(ctx, "", nil)
require.NoError(t, err)
require.Len(t, s.Tables, 1)
_, ok := s.Table(revision.Table)
require.True(t, ok)
cur, err := r.CurrentRevision(ctx)
require.True(t, errors.Is(err, migrate.ErrRevisionNotExist))
require.Nil(t, cur)
err = r.WriteRevision(ctx, &migrate.Revision{
Version: "1",
Description: "desc",
Type: migrate.RevisionTypeResolved,
ExecutedAt: time.Now(),
Hash: "hash",
OperatorVersion: "0.1.0",
})
require.NoError(t, err)
cur, err = r.CurrentRevision(ctx)
require.NoError(t, err)
require.Equal(t, "1", cur.Version)
next := *cur
next.Version = "2"
require.NoError(t, r.WriteRevision(ctx, &next))
cur, err = r.CurrentRevision(ctx)
require.NoError(t, err)
require.Equal(t, "2", cur.Version)
revs, err := r.ReadRevisions(ctx)
require.NoError(t, err)
require.Len(t, revs, 2)
require.Equal(t, "1", revs[0].Version)
require.Equal(t, "2", revs[1].Version)
id, err := r.ID(ctx, "v0.10.1")
require.NoError(t, err)
require.NotEmpty(t, id)
id1, err := r.ID(ctx, "v0.10.1")
require.NoError(t, err)
require.Equal(t, id, id1, "identifiers should be allocated only once")
// Identifier is not returned as a revision.
revs, err = r.ReadRevisions(ctx)
require.NoError(t, err)
require.Len(t, revs, 2, "identifiers should not be returned as revisions")
_, err = r.ReadRevision(ctx, revisionID)
require.Error(t, err)
err = r.DeleteRevision(ctx, revisionID)
require.Error(t, err)
err = r.WriteRevision(ctx, &migrate.Revision{Version: revisionID})
require.Error(t, err)
cur, err = r.CurrentRevision(ctx)
require.NoError(t, err)
require.Equal(t, "2", cur.Version)
require.NoError(t, r.DeleteRevision(ctx, "2"))
cur, err = r.CurrentRevision(ctx)
require.NoError(t, err)
require.Equal(t, "1", cur.Version)
require.NoError(t, r.DeleteRevision(ctx, "1"))
cur, err = r.CurrentRevision(ctx)
require.True(t, errors.Is(err, migrate.ErrRevisionNotExist))
require.Nil(t, cur)
revs, err = r.ReadRevisions(ctx)
require.NoError(t, err)
require.Len(t, revs, 0)
id1, err = r.ID(ctx, "v0.10.1")
require.NoError(t, err)
require.Equal(t, id, id1)
}
type (
mockDriver struct {
migrate.Driver
rrw migrate.RevisionReadWriter
}
mockrrw struct {
migrate.RevisionReadWriter
}
)
func (m *mockDriver) RevisionsReadWriter(context.Context, string) (migrate.RevisionReadWriter, error) {
return m.rrw, nil
}
func (*mockrrw) CurrentRevision(context.Context) (*migrate.Revision, error) { return nil, nil }
func (*mockrrw) Migrate(context.Context) error { return nil }
func (*mockrrw) ID(context.Context, string) (string, error) { return "", nil }
================================================
FILE: cmd/atlas/internal/migrate/testdata/broken/1.sql
================================================
CREATE TABLE `users` (`id` int NOT NULL PRIMARY KEY);
================================================
FILE: cmd/atlas/internal/migrate/testdata/broken/2.sql
================================================
ALTER TABLE `users` ADD COLUMN `happy` boolean NOT NULL DEFAULT true;
================================================
FILE: cmd/atlas/internal/migrate/testdata/broken/3.sql
================================================
CREATE TABLE `pets` (`id` int NOT NULL PRIMARY KEY);
THIS LINE ADDS A SYNTAX ERROR;
================================================
FILE: cmd/atlas/internal/migrate/testdata/broken/atlas.sum
================================================
h1:0YTkvowN+aAuYuJY5ZANPAq6QAZ0wAXunU9sUXsuZcI=
1.sql h1:twN+zPVp8JzWEUcPPfNIT6/62Wa08dfxxZhT4gZxBzg=
2.sql h1:KHLlrSPwSjbp4+KrpQHwYZf8zlSIiAR7MS3H2yd1yeE=
3.sql h1:iTKab5MEzWsTdVVDkCUWmateRs9XRNpal/cxqlCYsmQ=
================================================
FILE: cmd/atlas/internal/migrate/testdata/fixed/1.sql
================================================
CREATE TABLE `users` (`id` int NOT NULL PRIMARY KEY);
================================================
FILE: cmd/atlas/internal/migrate/testdata/fixed/2.sql
================================================
ALTER TABLE `users` ADD COLUMN `happy` boolean NOT NULL DEFAULT true;
================================================
FILE: cmd/atlas/internal/migrate/testdata/fixed/3.sql
================================================
CREATE TABLE `pets` (`id` int NOT NULL PRIMARY KEY);
ALTER TABLE `pets` ADD COLUMN `happy` boolean NULL;
================================================
FILE: cmd/atlas/internal/migrate/testdata/fixed/atlas.sum
================================================
h1:oNV0f9HzMMCf2pzF+sA6CmsSHGjdkWYmcTjoc/lWxLs=
1.sql h1:twN+zPVp8JzWEUcPPfNIT6/62Wa08dfxxZhT4gZxBzg=
2.sql h1:KHLlrSPwSjbp4+KrpQHwYZf8zlSIiAR7MS3H2yd1yeE=
3.sql h1:osHrPgu8uNgd6j09XCiyBQWWEh9aAmwjRgzdZZgm68M=
================================================
FILE: cmd/atlas/internal/migratelint/lint.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package migratelint
import (
"context"
"errors"
"fmt"
"os/exec"
"path/filepath"
"strings"
"ariga.io/atlas/cmd/atlas/internal/sqlparse"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlcheck"
"ariga.io/atlas/sql/sqlclient"
)
type (
// A ChangeDetector takes a migration directory and splits it into the "base" files (already merged) and new ones.
ChangeDetector interface {
// DetectChanges splits the files of a migration directory into the "base" files (already merged) and new ones.
DetectChanges(context.Context) ([]migrate.File, []migrate.File, error)
}
// A ChangeLoader takes a set of migration files and will create multiple schema.Changes out of it.
ChangeLoader interface {
// LoadChanges converts each of the given migration files into one Changes.
LoadChanges(context.Context, []migrate.File) (*Changes, error)
}
// Changes holds schema changes information returned by the loader.
Changes struct {
From, To *schema.Realm // Current and desired schema.
Files []*sqlcheck.File // Files for moving from current to desired state.
}
)
type (
// GitChangeDetector implements the ChangeDetector interface by utilizing a git repository.
GitChangeDetector struct {
work string // path to the git working directory (i.e. -C)
base string // name of the base branch (e.g. master)
path string // path of the migration directory relative to the repository root (in slash notation)
dir migrate.Dir // the migration directory to load migration files from
}
// GitChangeDetectorOption allows configuring GitChangeDetector with functional arguments.
GitChangeDetectorOption func(*GitChangeDetector) error
)
// NewGitChangeDetector configures a new GitChangeDetector.
func NewGitChangeDetector(dir migrate.Dir, opts ...GitChangeDetectorOption) (*GitChangeDetector, error) {
if dir == nil {
return nil, errors.New("internal/ci: dir cannot be nil")
}
d := &GitChangeDetector{dir: dir}
for _, opt := range opts {
if err := opt(d); err != nil {
return nil, err
}
}
if d.base == "" {
d.base = "master"
}
if d.path == "" {
d.path = "migrations"
}
return d, nil
}
// WithWorkDir configures the git working directory for a GitChangeDetector.
func WithWorkDir(work string) GitChangeDetectorOption {
return func(d *GitChangeDetector) error {
d.work = work
return nil
}
}
// WithBase configures the git base branch name for a GitChangeDetector.
func WithBase(base string) GitChangeDetectorOption {
return func(d *GitChangeDetector) error {
d.base = base
return nil
}
}
// WithMigrationsPath configures the path for the migration directory.
func WithMigrationsPath(path string) GitChangeDetectorOption {
return func(d *GitChangeDetector) error {
d.path = filepath.ToSlash(path)
return nil
}
}
// DetectChanges implements the ChangeDetector interface.
func (d *GitChangeDetector) DetectChanges(ctx context.Context) ([]migrate.File, []migrate.File, error) {
if _, err := exec.LookPath("git"); err != nil {
return nil, nil, fmt.Errorf("lookup git: %w", err)
}
var args []string
if d.work != "" {
args = append(args, "-C", d.work)
}
args = append(args, "--no-pager", "diff", "--name-only", "--diff-filter=A", d.base, "HEAD", d.path)
buf, err := exec.CommandContext(ctx, "git", args...).CombinedOutput()
if err != nil {
return nil, nil, fmt.Errorf("git diff: %w", err)
}
diff := strings.Split(string(buf), "\n")
names := make(map[string]struct{}, len(diff))
for i := range diff {
names[filepath.Base(diff[i])] = struct{}{}
}
files, err := d.dir.Files()
if err != nil {
return nil, nil, fmt.Errorf("reading migration directory: %w", err)
}
// Iterate over the migration files. If we find a file, that has been added in the diff between base and head,
// every migration file preceding it can be considered old, the file itself and everything thereafter new,
// since Atlas assumes a linear migration history.
for i, f := range files {
if _, ok := names[f.Name()]; ok {
return files[:i], files[i:], nil
}
}
return files, nil, nil
}
var (
_ ChangeDetector = (*GitChangeDetector)(nil)
_ ChangeDetector = (*DirChangeDetector)(nil)
)
// A DirChangeDetector implements the ChangeDetector
// interface by comparing two migration directories.
type DirChangeDetector struct {
// Base and Head are the migration directories to compare.
// Base represents the current state, Head the desired state.
Base, Head migrate.Dir
}
// DetectChanges implements migratelint.ChangeDetector.
func (d DirChangeDetector) DetectChanges(context.Context) ([]migrate.File, []migrate.File, error) {
baseS, err := d.Base.Checksum()
if err != nil {
return nil, nil, err
}
headS, err := d.Head.Checksum()
if err != nil {
return nil, nil, err
}
files, err := d.Head.Files()
if err != nil {
return nil, nil, err
}
for i := range headS {
if len(baseS)-1 < i || baseS[i] != headS[i] {
return files[:i], files[i:], nil
}
}
return files, nil, nil
}
// latestChange implements the ChangeDetector by selecting the latest N files.
type latestChange struct {
n int // number of (latest) files considered new.
dir migrate.Dir // migration directory to load migration files from.
}
// LatestChanges implements the ChangeDetector interface by selecting the latest N files as new.
// It is useful for executing analysis on files in development before they are committed or on
// all files in a directory.
func LatestChanges(dir migrate.Dir, n int) ChangeDetector {
return &latestChange{n: n, dir: dir}
}
// DetectChanges implements the ChangeDetector interface.
func (d *latestChange) DetectChanges(context.Context) ([]migrate.File, []migrate.File, error) {
files, err := d.dir.Files()
if err != nil {
return nil, nil, fmt.Errorf("internal/ci: reading migration directory: %w", err)
}
// In case n is -1 or greater than the
// number of files, return all files.
if len(files) <= d.n || d.n < 0 {
return nil, files, nil
}
return files[:len(files)-d.n], files[len(files)-d.n:], nil
}
// DevLoader implements the ChangesLoader interface using a dev-driver.
type DevLoader struct {
// Dev environment used as a sandbox instantiated to the starting point (e.g. base branch).
Dev *sqlclient.Client
}
// LoadChanges implements the ChangesLoader interface.
func (d *DevLoader) LoadChanges(ctx context.Context, base, files []migrate.File) (diff *Changes, err error) {
unlock, err := d.lock(ctx)
if err != nil {
return nil, err
}
defer unlock()
// Clean up after ourselves.
restore, err := d.Dev.Driver.Snapshot(ctx)
if err != nil {
return nil, fmt.Errorf("taking database snapshot: %w", err)
}
defer func() {
if err2 := restore(ctx); err2 != nil {
err = errors.Join(err, fmt.Errorf("restore dev-database snapshot: %w", err2))
}
}()
current, err := d.base(ctx, base)
if err != nil {
return nil, err
}
diff = &Changes{
From: current,
Files: make([]*sqlcheck.File, len(files)),
}
cks := make([]int, 0, len(files))
for i, f := range files {
diff.Files[i] = &sqlcheck.File{
File: f,
From: current,
Parser: sqlparse.ParserFor(d.Dev.Name),
}
// Skip checkpoint files and process them separately at the end.
if ck, ok := f.(migrate.CheckpointFile); ok && ck.IsCheckpoint() {
cks = append(cks, i)
continue
}
// A common case is when importing a project to Atlas the baseline
// migration file might be very long. However, since we execute on
// a clean database, the per-statement analysis is not needed.
if len(base) == 0 && i == 0 {
current, err = d.first(ctx, diff.Files[i], current)
} else {
current, err = d.next(ctx, diff.Files[i], current)
}
if err != nil {
return nil, err
}
diff.Files[i].To = current
}
diff.To = current
// For each checkpoint file, restore the dev environment
// to the base point (clean) and load its changes.
for _, i := range cks {
if err := restore(ctx); err != nil {
return nil, err
}
current, err := d.inspect(ctx)
if err != nil {
return nil, err
}
if _, err := d.next(ctx, diff.Files[i], current); err != nil {
return nil, err
}
}
return diff, nil
}
// base brings the dev environment to the base point and returns its state. It skips to the first checkpoint,
// if there is one, assuming the history is replay-able before that point as this was tested in previous runs.
func (d *DevLoader) base(ctx context.Context, base []migrate.File) (*schema.Realm, error) {
if i := migrate.FilesLastIndex(base, func(f migrate.File) bool {
ck, ok := f.(migrate.CheckpointFile)
return ok && ck.IsCheckpoint()
}); i != -1 {
base = base[i:]
}
for _, f := range base {
stmts, err := d.stmts(ctx, f, false)
if err != nil {
return nil, err
}
for _, s := range stmts {
if _, err := d.Dev.ExecContext(ctx, s.Text); err != nil {
return nil, &FileError{File: f.Name(), Err: fmt.Errorf("executing statement: %w", err), Pos: s.Pos}
}
}
}
return d.inspect(ctx)
}
// first is a version of "next" but is used when linting the first migration file. In this case we do not
// need to analyze each statement, but the entire result of the file (much faster). For example, a baseline
// file or the first migration when running 'schema apply' might contain thousands of lines.
func (d *DevLoader) first(ctx context.Context, f *sqlcheck.File, start *schema.Realm) (current *schema.Realm, err error) {
stmts, err := d.stmts(ctx, f.File, true)
if err != nil {
return nil, err
}
// We define the max number of apply-inspect-diff cycles to 10,
// to limit our linting time for baseline/first migration files.
const maxStmtLoop = 10
if len(stmts) <= maxStmtLoop {
return d.nextStmts(ctx, f, stmts, start)
}
for _, s := range stmts {
if _, err := d.Dev.ExecContext(ctx, s.Text); err != nil {
return nil, &FileError{File: f.Name(), Err: fmt.Errorf("executing statement: %s: %w", s.Text, err), Pos: s.Pos}
}
}
if current, err = d.inspect(ctx); err != nil {
return nil, err
}
changes, err := d.Dev.RealmDiff(start, current)
if err != nil {
return nil, err
}
f.Changes = append(f.Changes, &sqlcheck.Change{
Changes: changes,
Stmt: &migrate.Stmt{
Pos: 0, // Beginning of the file.
},
})
f.Sum = changes
return current, nil
}
// next returns the next state of the database after executing the statements in
// the file. The changes detected by the statements are attached to the file.
func (d *DevLoader) next(ctx context.Context, f *sqlcheck.File, start *schema.Realm) (*schema.Realm, error) {
stmts, err := d.stmts(ctx, f.File, true)
if err != nil {
return nil, err
}
return d.nextStmts(ctx, f, stmts, start)
}
// nextStmts is a version of "next" but accepts the statements to execute.
func (d *DevLoader) nextStmts(ctx context.Context, f *sqlcheck.File, stmts []*migrate.Stmt, start *schema.Realm) (current *schema.Realm, err error) {
current = start
for _, s := range stmts {
if _, err := d.Dev.ExecContext(ctx, s.Text); err != nil {
return nil, &FileError{File: f.Name(), Err: fmt.Errorf("executing statement: %s: %w", s.Text, err), Pos: s.Pos}
}
next, err := d.inspect(ctx)
if err != nil {
return nil, err
}
changes, err := d.Dev.RealmDiff(current, next)
if err != nil {
return nil, err
}
current = next
f.Changes = append(f.Changes, &sqlcheck.Change{
Stmt: s,
Changes: d.mayFix(s.Text, changes),
})
}
if f.Sum, err = d.Dev.RealmDiff(start, current); err != nil {
return nil, err
}
return current, nil
}
// mayFix uses the sqlparse package for fixing or attaching more info to the changes.
func (d *DevLoader) mayFix(stmt string, changes schema.Changes) schema.Changes {
p := sqlparse.ParserFor(d.Dev.Name)
if p == nil {
return changes
}
if fixed, err := p.FixChange(d.Dev.Driver, stmt, changes); err == nil {
return fixed
}
return changes
}
// inspect the realm and filter by schema if we are connected to one.
func (d *DevLoader) inspect(ctx context.Context) (*schema.Realm, error) {
if d.Dev.URL.Schema == "" {
return d.Dev.InspectRealm(ctx, &schema.InspectRealmOption{})
}
ns, err := d.Dev.InspectSchema(ctx, "", &schema.InspectOptions{})
if err != nil {
return nil, err
}
// Normalize the returned realm to
// look like InspectRealm output.
if ns.Name == "" {
ns.Name = d.Dev.URL.Schema
}
if ns.Realm == nil {
ns.Realm = schema.NewRealm(ns)
}
return ns.Realm, nil
}
// lock database so no one else interferes with our change detection.
func (d *DevLoader) lock(ctx context.Context) (schema.UnlockFunc, error) {
name := "atlas_lint"
// In case the client is connected to specific schema,
// minimize the lock resolution to the schema name.
if s := d.Dev.URL.Schema; s != "" {
name = fmt.Sprintf("%s_%s", name, s)
}
unlock, err := d.Dev.Driver.Lock(ctx, name, 0)
if err != nil {
return nil, fmt.Errorf("acquiring database lock: %w", err)
}
return unlock, nil
}
// FileError represents an error that occurred while processing a file.
type FileError struct {
File string
Err error // Atlas or database error.
Pos int // Position error, if known.
}
func (e FileError) Error() string { return e.Err.Error() }
func (e FileError) Unwrap() error { return e.Err }
================================================
FILE: cmd/atlas/internal/migratelint/lint_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package migratelint
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/fs"
"slices"
"strings"
"text/template"
"time"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/sqlcheck"
"ariga.io/atlas/sql/sqlclient"
"github.com/fatih/color"
)
// Runner is used to execute migration linting.
type Runner struct {
// DevClient configures the "dev driver" to calculate
// migration changes by the driver.
Dev *sqlclient.Client
// RunChangeDetector configures the ChangeDetector to
// be used by the runner.
ChangeDetector ChangeDetector
// Dir is used for scanning and validating the migration directory.
Dir migrate.Dir
// Analyzers defines the analysis to run on each migration file.
Analyzers []sqlcheck.Analyzer
// ReportWriter writes the summary report.
ReportWriter ReportWriter
// summary report. reset on each run.
sum *SummaryReport
}
// Run executes migration linting.
func (r *Runner) Run(ctx context.Context) error {
switch err := r.summary(ctx); err.(type) {
case nil:
if err := r.ReportWriter.WriteReport(r.sum); err != nil {
return err
}
// If any of the analyzers or the steps
// returns an error, fail silently.
for _, f := range r.sum.Files {
if f.Error != "" {
return SilentError{error: errors.New(f.Error)}
}
}
for _, s := range r.sum.Steps {
// Currently, we piggyback step errors
// (such as non-linear) on FileReport.
if s.Result != nil && s.Error != "" {
return SilentError{error: errors.New(s.Error)}
}
}
return nil
case *FileError:
if err := r.ReportWriter.WriteReport(r.sum); err != nil {
return err
}
return SilentError{error: err}
default:
return err
}
}
// A list of steps in CI report.
const (
StepIntegrityCheck = "Migration Integrity Check"
StepDetectChanges = "Detect New Migration Files"
StepLoadChanges = "Replay Migration Files"
StepAnalyzeFile = "Analyze %s"
)
func (r *Runner) summary(ctx context.Context) error {
r.sum = NewSummaryReport(r.Dev, r.Dir)
defer func() { r.sum.End = time.Now() }()
// Integrity check.
switch err := migrate.Validate(r.Dir); {
case errors.Is(err, migrate.ErrChecksumNotFound):
case err != nil:
var (
err = &FileError{File: migrate.HashFileName, Err: err}
rep = &FileReport{Name: migrate.HashFileName, Error: err.Error()}
)
if csErr := (&migrate.ChecksumError{}); errors.As(err, &csErr) {
err.Pos = csErr.Pos
rep = &FileReport{
Name: migrate.HashFileName,
Error: fmt.Sprintf("%s (atlas.sum): L%d: %s was %s", csErr, csErr.Line, csErr.File, csErr.Reason),
}
}
r.sum.Files = append(r.sum.Files, rep)
return r.sum.StepError(StepIntegrityCheck, fmt.Sprintf("File %s is invalid", migrate.HashFileName), err)
default:
// If the hash file exists, it is valid.
if _, err := fs.Stat(r.Dir, migrate.HashFileName); err == nil {
r.sum.StepResult(StepIntegrityCheck, fmt.Sprintf("File %s is valid", migrate.HashFileName), nil)
}
}
// Detect new migration files.
base, feat, err := r.ChangeDetector.DetectChanges(ctx)
switch err := err.(type) {
// No error.
case nil:
r.sum.StepResult(StepDetectChanges, fmt.Sprintf("Found %d new migration files (from %d total)", len(feat), len(base)+len(feat)), nil)
// Error that should be reported, but not halt the lint.
case interface{ StepReport() *StepReport }:
r.sum.Steps = append(r.sum.Steps, err.StepReport())
default:
return r.sum.StepError(StepDetectChanges, "Failed find new migration files", err)
}
if len(base) > 0 {
r.sum.FromV = base[len(base)-1].Version()
}
if len(feat) > 0 {
r.sum.ToV = feat[len(feat)-1].Version()
}
r.sum.TotalFiles = len(feat)
// Load files into changes.
l := &DevLoader{Dev: r.Dev}
diff, err := l.LoadChanges(ctx, base, feat)
if err != nil {
if fr := (&FileError{}); errors.As(err, &fr) {
r.sum.Files = append(r.sum.Files, &FileReport{Name: fr.File, Error: err.Error()})
}
return r.sum.StepError(StepLoadChanges, "Failed loading changes on dev database", err)
}
r.sum.StepResult(StepLoadChanges, fmt.Sprintf("Loaded %d changes on dev database", len(diff.Files)), nil)
r.sum.WriteSchema(r.Dev, diff)
// Analyze files.
return r.analyze(ctx, diff.Files)
}
// analyze runs the analysis on the given files.
func (r *Runner) analyze(ctx context.Context, files []*sqlcheck.File) error {
for _, f := range files {
var (
es []string
nl = nolintRules(f)
fr = NewFileReport(f)
)
if nl.ignored {
continue
}
for _, az := range r.Analyzers {
err := func(az sqlcheck.Analyzer) (rerr error) {
defer func() {
if rc := recover(); rc != nil {
var name string
if n, ok := az.(sqlcheck.NamedAnalyzer); ok {
name = fmt.Sprintf(" (%s)", n.Name())
}
rerr = fmt.Errorf("skip crashed analyzer %s: %v", name, rc)
}
}()
return az.Analyze(ctx, &sqlcheck.Pass{
File: f,
Dev: r.Dev,
Reporter: nl.reporterFor(fr, az),
})
}(az)
// If the last report was skipped,
// skip emitting its error.
if err != nil && !nl.skipped {
es = append(es, err.Error())
}
}
fr.Error = strings.Join(es, "; ")
r.sum.Files = append(r.sum.Files, fr)
r.sum.StepResult(
fmt.Sprintf(StepAnalyzeFile, f.Name()),
fmt.Sprintf("%d reports were found in analysis", len(fr.Reports)),
fr,
)
}
return nil
}
var (
// TemplateFuncs are global functions available in templates.
TemplateFuncs = template.FuncMap{
"json": func(v any, args ...string) (string, error) {
var (
b []byte
err error
)
switch len(args) {
case 0:
b, err = json.Marshal(v)
case 1:
b, err = json.MarshalIndent(v, "", args[0])
default:
b, err = json.MarshalIndent(v, args[0], args[1])
}
return string(b), err
},
"sub": func(i, j int) int { return i - j },
"add": func(i, j int) int { return i + j },
"repeat": strings.Repeat,
"join": strings.Join,
"underline": color.New(color.Underline, color.Attribute(90)).Sprint,
"gray": color.New(color.Reset, color.Attribute(90)).Sprint,
"lower": strings.ToLower,
"maxWidth": func(s string, n int) []string {
var (
j, k int
words = strings.Fields(s)
lines = make([]string, 0, len(words))
)
for i := 0; i < len(words); i++ {
if k+len(words[i]) > n {
lines = append(lines, strings.Join(words[j:i], " "))
k, j = 0, i
}
k += len(words[i])
}
return append(lines, strings.Join(words[j:], " "))
},
"cyan": color.CyanString,
"green": color.HiGreenString,
"red": color.HiRedString,
"redBgWhiteFg": color.New(color.FgHiWhite, color.BgHiRed).SprintFunc(),
"yellow": color.YellowString,
"colorize": func(cc, text string) string {
switch cc {
case "cyan":
return color.CyanString(text)
case "green":
return color.HiGreenString(text)
case "red":
return color.HiRedString(text)
case "yellow":
return color.YellowString(text)
default:
return text
}
},
}
// DefaultTemplate is the default template used by the CI job.
DefaultTemplate = template.Must(template.New("report").
Funcs(TemplateFuncs).
Parse(`
{{- if or .Files .NonFileReports }}
{{- $total := len .Files }}{{- with .TotalFiles }}{{- $total = . }}{{ end }}
{{- $s := "s" }}{{ if eq $total 1 }}{{ $s = "" }}{{ end }}
{{- if and .FromV .ToV }}
{{- printf "Analyzing changes from version %s to %s" (cyan .FromV) (cyan .ToV) }}
{{- else if .ToV }}
{{- printf "Analyzing changes until version %s" (cyan .ToV) }}
{{- else }}
{{- printf "Analyzing changes" }}
{{- end }}
{{- if $total }}
{{- printf " (%d migration%s in total):\n" $total $s }}
{{- else }}
{{- println ":" }}
{{- end }}
{{- println }}
{{- with .NonFileReports }}
{{- range $i, $s := . }}
{{- println (yellow " --") (lower $s.Name) }}
{{- range $i, $r := $s.Result.Reports }}
{{- if $r.Text }}
{{- printf " %s %s:\n" (yellow "--") $r.Text }}
{{- end }}
{{- range $d := $r.Diagnostics }}
{{- $prefix := printf " %s " (cyan "--") }}
{{- print $prefix }}
{{- $lines := maxWidth $d.Text (sub 85 (len $prefix)) }}
{{- range $i, $line := $lines }}{{- if $i }}{{- print " " }}{{- end }}{{- println $line }}{{- end }}
{{- end }}
{{- $fixes := $s.Result.SuggestedFixes }}
{{- if $fixes }}
{{- $s := "es" }}{{- if eq (len $fixes) 1 }}{{ $s = "" }}{{ end }}
{{- printf " %s suggested fix%s:\n" (yellow "--") $s }}
{{- range $f := $fixes }}
{{- $prefix := printf " %s " (cyan "->") }}
{{- print $prefix }}
{{- $lines := maxWidth $f.Message (sub 85 (len $prefix)) }}
{{- range $i, $line := $lines }}{{- if $i }}{{- print " " }}{{- end }}{{- println $line }}{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- println }}
{{- end }}
{{- range $i, $f := .Files }}
{{- /* Replay or checksum errors. */ -}}
{{- if and $f.Error (eq $f.File nil) (eq $i (sub (len $.Files) 1)) }}
{{- printf " %s\n\n" (redBgWhiteFg (printf "Error: %s" $f.Error)) }}
{{- break }}
{{- end }}
{{- $heading := printf "analyzing version %s" (cyan $f.Version) }}
{{- $headinglen := len (printf "analyzing version %s" $f.Version) }}
{{- println (yellow " --") $heading }}
{{- if and $f.Error (not $f.Reports) }}
{{- printf "Error: %s\n" $f.Name $f.Error }}
{{- continue }}
{{- end }}
{{- range $i, $r := $f.Reports }}
{{- if $r.Text }}
{{- printf " %s %s:\n" (yellow "--") $r.Text }}
{{- else if $r.Diagnostics }}
{{- printf " %s Unnamed diagnostics detected:\n" (yellow "--") }}
{{- end }}
{{- range $d := $r.Diagnostics }}
{{- $prefix := printf " %s L%d: " (cyan "--") ($f.Line $d.Pos) }}
{{- print $prefix }}
{{- $link := (underline (print "https://atlasgo.io/lint/analyzers#" $d.Code)) }}{{ if not $d.Code }}{{ $link = "" }}{{ end }}
{{- $text := printf "%s %s" $d.Text $link }}
{{- $lines := maxWidth $text (sub 85 (len $prefix)) }}
{{- range $i, $line := $lines }}{{- if $i }}{{- print " " }}{{- end }}{{- println $line }}{{- end }}
{{- end }}
{{- else }}
{{- printf " %s no diagnostics found\n" (cyan "--") }}
{{- end }}
{{- $fixes := $f.SuggestedFixes }}
{{- if $fixes }}
{{- $s := "es" }}{{- if eq (len $fixes) 1 }}{{ $s = "" }}{{ end }}
{{- printf " %s suggested fix%s:\n" (yellow "--") $s }}
{{- range $f := $fixes }}
{{- $prefix := printf " %s " (cyan "->") }}
{{- print $prefix }}
{{- $lines := maxWidth $f.Message (sub 85 (len $prefix)) }}
{{- range $i, $line := $lines }}{{- if $i }}{{- print " " }}{{- end }}{{- println $line }}{{- end }}
{{- end }}
{{- end }}
{{- if or (not $f.Error) $f.Reports }}
{{- printf " %s ok (%s)\n" (yellow "--") (yellow (.End.Sub .Start).String) }}
{{- end }}
{{- println }}
{{- end }}
{{- println (cyan " -------------------------") }}
{{- printf " %s %s\n" (yellow "--") (.End.Sub .Start).String }}
{{- with .VersionStatuses }}
{{- printf " %s %s\n" (yellow "--") . }}
{{- end }}
{{- with .TotalChanges }}
{{- $s := "s" }}{{ if eq . 1 }}{{ $s = "" }}{{ end }}
{{- printf " %s %d schema change%s\n" (yellow "--") . $s }}
{{- end }}
{{- with .DiagnosticsCount }}
{{- $s := "s" }}{{ if eq . 1 }}{{ $s = "" }}{{ end }}
{{- printf " %s %d diagnostic%s\n" (yellow "--") . $s }}
{{- end }}
{{- end -}}
`))
// JSONTemplate is the JSON template used by CI wrappers.
JSONTemplate = template.Must(template.New("json").
Funcs(TemplateFuncs).
Parse("{{ json . }}"))
)
type (
// A SummaryReport contains a summary of the analysis of all files.
// It is used as an input to templates to report the CI results.
SummaryReport struct {
URL string `json:"URL,omitempty"` // URL of the report, if exists.
// Env holds the environment information.
Env struct {
Driver string `json:"Driver,omitempty"` // Driver name.
URL *sqlclient.URL `json:"URL,omitempty"` // URL to dev database.
Dir string `json:"Dir,omitempty"` // Path to migration directory.
}
// Schema versions found by the runner.
Schema struct {
Current string `json:"Current,omitempty"` // Current schema.
Desired string `json:"Desired,omitempty"` // Desired schema.
}
// Steps of the analysis. Added in verbose mode.
Steps []*StepReport `json:"Steps,omitempty"`
// Files reports. Non-empty in case there are findings.
Files []*FileReport `json:"Files,omitempty"`
// Logging only info.
Start time.Time `json:"-"` // Start time of the analysis.
End time.Time `json:"-"` // End time of the analysis.
FromV, ToV string `json:"-"` // From and to versions.
TotalFiles int `json:"-"` // Total number of files to analyze.
// A warning to be printed to the terminal, such as a license warning.
Warning *struct {
Title string
Text string
} `json:"-"`
}
// FileChange specifies whether the file was added, deleted or changed.
FileChange string
// StepReport contains a summary of the analysis of a single step.
StepReport struct {
Name string `json:"Name,omitempty"` // Step name.
Text string `json:"Text,omitempty"` // Step description.
Error string `json:"Error,omitempty"` // Error that cause the execution to halt.
Result *FileReport `json:"Result,omitempty"` // Result of the step. For example, a diagnostic.
// A warning to be printed to the terminal, such as a license warning.
Warning struct {
Title string `json:"Title,omitempty"`
Text string `json:"Text,omitempty"`
} `json:"-"`
}
// FileReport contains a summary of the analysis of a single file.
FileReport struct {
Name string `json:"Name,omitempty"` // Name of the file.
Text string `json:"Text,omitempty"` // Contents of the file.
Reports []sqlcheck.Report `json:"Reports,omitempty"` // List of reports.
Error string `json:"Error,omitempty"` // File specific error.
Change FileChange `json:"Change,omitempty"` // Change of the file.
// Logging only info.
Start time.Time `json:"-"` // Start time of the analysis.
End time.Time `json:"-"` // End time of the analysis.
*sqlcheck.File `json:"-"` // Underlying file.
}
// ReportWriter is a type of report writer that writes a summary of analysis reports.
ReportWriter interface {
WriteReport(*SummaryReport) error
}
// A TemplateWriter is a type of writer that writes output according to a template.
TemplateWriter struct {
T *template.Template
W io.Writer
}
// SilentError is returned in case the wrapped error is already
// printed by the runner and should not be printed by its caller
SilentError struct{ error }
)
const (
FileChangeAdded FileChange = "ADDED"
FileChangeDeleted FileChange = "DELETED"
FileChangeModified FileChange = "MODIFIED"
)
// NewSummaryReport returns a new SummaryReport.
func NewSummaryReport(c *sqlclient.Client, dir migrate.Dir) *SummaryReport {
sum := &SummaryReport{
Start: time.Now(),
Env: struct {
Driver string `json:"Driver,omitempty"`
URL *sqlclient.URL `json:"URL,omitempty"`
Dir string `json:"Dir,omitempty"`
}{
Driver: c.Name,
URL: c.URL,
},
Files: make([]*FileReport, 0),
}
if p, ok := dir.(interface{ Path() string }); ok {
sum.Env.Dir = p.Path()
}
return sum
}
// StepResult appends step result to the summary.
func (r *SummaryReport) StepResult(name, text string, result *FileReport) {
if result != nil {
result.End = time.Now()
}
r.Steps = append(r.Steps, &StepReport{
Name: name,
Text: text,
Result: result,
})
}
// StepError appends step error to the summary.
func (r *SummaryReport) StepError(name, text string, err error) error {
r.Steps = append(r.Steps, &StepReport{
Name: name,
Text: text,
Error: err.Error(),
})
return err
}
// WriteSchema writes the current and desired schema to the summary.
func (r *SummaryReport) WriteSchema(c *sqlclient.Client, diff *Changes) {
if curr, err := c.MarshalSpec(diff.From); err == nil {
r.Schema.Current = string(curr)
}
if desired, err := c.MarshalSpec(diff.To); err == nil {
r.Schema.Desired = string(desired)
}
}
// DiagnosticsCount returns the total number of diagnostics in the report.
func (r *SummaryReport) DiagnosticsCount() int {
var n int
for _, f := range r.Files {
for _, r := range f.Reports {
n += len(r.Diagnostics)
}
}
return n
}
// VersionStatuses returns statuses description of all versions (migration files).
func (r *SummaryReport) VersionStatuses() string {
var ok, errs, warns int
for _, f := range r.Files {
switch {
case f.Error != "":
errs++
case len(f.Reports) > 0:
warns++
default:
ok++
}
}
parts := make([]string, 0, 3)
for _, s := range []struct {
n int
s string
}{
{ok, "ok"},
{warns, "with warnings"},
{errs, "with errors"},
} {
switch {
case s.n == 0:
case s.n == 1 && len(parts) == 0:
parts = append(parts, fmt.Sprintf("1 version %s", s.s))
case s.n > 1 && len(parts) == 0:
parts = append(parts, fmt.Sprintf("%d versions %s", s.n, s.s))
default:
parts = append(parts, fmt.Sprintf("%d %s", s.n, s.s))
}
}
return strings.Join(parts, ", ")
}
// TotalChanges returns the total number of changes that were analyzed.
func (r *SummaryReport) TotalChanges() int {
var n int
for _, f := range r.Files {
if f.File != nil {
for _, c := range f.File.Changes {
n += len(c.Changes)
}
}
}
return n
}
// NonFileReports returns reports that are not related to a file,
// but more general, like non-linear/additive changes.
func (r *SummaryReport) NonFileReports() (rs []*StepReport) {
for _, s := range r.Steps {
if r1 := s.Result; r1 != nil && r1.File == nil && len(r1.Reports) > 0 {
rs = append(rs, s)
}
}
return rs
}
// NewFileReport returns a new FileReport.
func NewFileReport(f *sqlcheck.File) *FileReport {
return &FileReport{Name: f.Name(), Text: string(f.Bytes()), Start: time.Now(), File: f}
}
// Line returns the line number from a position.
func (f *FileReport) Line(pos int) int {
return strings.Count(f.Text[:pos], "\n") + 1
}
// SuggestedFixes returns the list of suggested fixes for a specific report.
func (f *FileReport) SuggestedFixes() []sqlcheck.SuggestedFix {
var fixes []sqlcheck.SuggestedFix
for _, r := range f.Reports {
// Report-level fixes.
for _, x := range r.SuggestedFixes {
if x.Message != "" {
fixes = append(fixes, x)
}
}
// Diagnostic-level fixes.
for _, d := range r.Diagnostics {
for _, x := range d.SuggestedFixes {
if x.Message != "" {
fixes = append(fixes, x)
}
}
}
}
return fixes
}
// WriteReport implements sqlcheck.ReportWriter.
func (f *FileReport) WriteReport(r sqlcheck.Report) {
f.Reports = append(f.Reports, r)
}
// WriteReport implements ReportWriter.
func (w *TemplateWriter) WriteReport(r *SummaryReport) error {
return w.T.Execute(w.W, r)
}
func (err SilentError) Unwrap() error { return err.error }
func nolintRules(f *sqlcheck.File) *skipRules {
s := &skipRules{pos2rules: make(map[int][]string)}
if l, ok := f.File.(*migrate.LocalFile); ok {
ds := l.Directive("nolint")
// A file directive without specific classes/codes
// (e.g. atlas:nolint) ignores the entire file.
if s.ignored = len(ds) == 1 && ds[0] == ""; s.ignored {
return s
}
// A file directive with specific classes/codes applies these
// rules on all statements (e.g., atlas:nolint destructive).
for _, d := range ds {
for _, c := range f.Changes {
s.pos2rules[c.Stmt.Pos] = append(s.pos2rules[c.Stmt.Pos], strings.Split(d, " ")...)
}
}
}
for _, c := range f.Changes {
// A list of changes that were loaded in a batch (no statements per change).
if c.Stmt != nil {
for _, d := range c.Stmt.Directive("nolint") {
s.pos2rules[c.Stmt.Pos] = append(s.pos2rules[c.Stmt.Pos], strings.Split(d, " ")...)
}
}
}
return s
}
type skipRules struct {
pos2rules map[int][]string // statement positions to rules
ignored bool // file is ignored. i.e., no analysis is performed
skipped bool // if the last report was skipped by the rules
}
func (s *skipRules) reporterFor(rw sqlcheck.ReportWriter, az sqlcheck.Analyzer) sqlcheck.ReportWriter {
return sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {
var (
ds = make([]sqlcheck.Diagnostic, 0, len(r.Diagnostics))
az, ok = az.(sqlcheck.NamedAnalyzer)
)
for _, d := range r.Diagnostics {
switch rules := s.pos2rules[d.Pos]; {
case
// A directive without specific classes/codes
// (e.g. atlas:nolint) ignore all diagnostics.
len(rules) == 1 && rules[0] == "",
// Match a specific code/diagnostic. e.g. atlas:nolint DS101.
slices.Contains(rules, d.Code),
// Skip the entire analyzer (class of changes).
ok && slices.Contains(rules, az.Name()):
default:
ds = append(ds, d)
}
}
if s.skipped = len(ds) == 0; !s.skipped {
rw.WriteReport(sqlcheck.Report{Text: r.Text, Diagnostics: ds})
}
})
}
func (d *DevLoader) stmts(_ context.Context, f migrate.File, _ bool) ([]*migrate.Stmt, error) {
stmts, err := migrate.FileStmtDecls(d.Dev.Driver, f)
if err != nil {
return nil, &FileError{File: f.Name(), Err: fmt.Errorf("scanning statements: %w", err)}
}
return stmts, nil
}
================================================
FILE: cmd/atlas/internal/migratelint/lint_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package migratelint_test
import (
"context"
"os"
"os/exec"
"path/filepath"
"strconv"
"testing"
"time"
"ariga.io/atlas/cmd/atlas/internal/migratelint"
"ariga.io/atlas/sql/migrate"
_ "ariga.io/atlas/sql/sqlite"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
)
func TestGitChangeDetector(t *testing.T) {
// Prepare environment.
root := filepath.Join(t.TempDir(), t.Name(), strconv.FormatInt(time.Now().Unix(), 10))
mdir := filepath.Join(root, "migrations")
require.NoError(t, os.MkdirAll(mdir, 0755))
git := func(args ...string) {
out, err := exec.Command("git", append([]string{"-C", root}, args...)...).CombinedOutput()
require.NoError(t, err, string(out))
}
git("init")
// Config a fake Git user for the working directory.
git("config", "user.name", "a8m")
git("config", "user.email", "a8m@atlasgo.io")
require.NoError(t, os.WriteFile(filepath.Join(mdir, "1_applied.sql"), []byte("1_applied.sql"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(mdir, "2_applied.sql"), []byte("2_applied.sql"), 0644))
git("add", ".")
git("commit", "-m", "applied migrations")
git("checkout", "-b", "feature")
require.NoError(t, os.WriteFile(filepath.Join(mdir, "3_new.sql"), []byte("3_new.sql"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(mdir, "4_new.sql"), []byte("4_new.sql"), 0644))
git("add", ".")
git("commit", "-am", "new migrations")
// Test change detector.
dir, err := migrate.NewLocalDir(mdir)
require.NoError(t, err)
cs, err := migratelint.NewGitChangeDetector(dir, migratelint.WithWorkDir(root))
require.NoError(t, err)
base, feat, err := cs.DetectChanges(context.Background())
require.NoError(t, err)
require.Len(t, base, 2)
require.Len(t, feat, 2)
require.Equal(t, "1_applied.sql", base[0].Name())
require.Equal(t, "2_applied.sql", base[1].Name())
require.Equal(t, "3_new.sql", feat[0].Name())
require.Equal(t, "4_new.sql", feat[1].Name())
require.NoError(t, os.WriteFile(filepath.Join(mdir, "5_new.sql"), []byte("5_new.sql"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(mdir, "6_new.sql"), []byte("6_new.sql"), 0644))
git("checkout", "-b", "feature-1")
git("add", ".")
git("commit", "-am", "new migrations")
base, feat, err = cs.DetectChanges(context.Background())
require.NoError(t, err)
require.Len(t, base, 2)
require.Len(t, feat, 4)
require.Equal(t, "5_new.sql", feat[2].Name())
require.Equal(t, "6_new.sql", feat[3].Name())
// Compare feature and feature-1.
cs, err = migratelint.NewGitChangeDetector(dir, migratelint.WithWorkDir(root), migratelint.WithBase("feature"))
require.NoError(t, err)
base, feat, err = cs.DetectChanges(context.Background())
require.NoError(t, err)
require.Len(t, base, 4)
require.Len(t, feat, 2)
require.Equal(t, "1_applied.sql", base[0].Name())
require.Equal(t, "2_applied.sql", base[1].Name())
require.Equal(t, "3_new.sql", base[2].Name())
require.Equal(t, "4_new.sql", base[3].Name())
require.Equal(t, "5_new.sql", feat[0].Name())
require.Equal(t, "6_new.sql", feat[1].Name())
}
func TestDirChangeDetector(t *testing.T) {
base, head := &migrate.MemDir{}, &migrate.MemDir{}
require.NoError(t, base.WriteFile("1.sql", []byte("create table t1 (id int)")))
require.NoError(t, head.WriteFile("1.sql", []byte("create table t1 (id int)")))
require.NoError(t, base.WriteFile("2.sql", []byte("create table t2 (id int)")))
require.NoError(t, head.WriteFile("2.sql", []byte("create table t2 (id int)")))
baseF, newF, err := migratelint.DirChangeDetector{Base: base, Head: head}.DetectChanges(context.Background())
require.NoError(t, err)
require.Len(t, baseF, 2)
require.Empty(t, newF)
require.NoError(t, head.WriteFile("3.sql", []byte("create table t3 (id int)")))
baseF, newF, err = migratelint.DirChangeDetector{Base: base, Head: head}.DetectChanges(context.Background())
require.NoError(t, err)
require.Len(t, baseF, 2)
require.Len(t, newF, 1)
}
func TestLatestChanges(t *testing.T) {
dir := &migrate.MemDir{}
require.NoError(t, dir.WriteFile("1.sql", []byte("CREATE TABLE t1 (id INT)")))
require.NoError(t, dir.WriteFile("2.sql", []byte("CREATE TABLE t2 (id INT)")))
base, feat, err := migratelint.LatestChanges(dir, 0).DetectChanges(context.Background())
require.NoError(t, err)
files, err := dir.Files()
require.NoError(t, err)
require.Equal(t, files, base)
require.Empty(t, feat)
base, feat, err = migratelint.LatestChanges(dir, 2).DetectChanges(context.Background())
require.NoError(t, err)
require.Empty(t, base)
require.Equal(t, files, feat)
base, feat, err = migratelint.LatestChanges(dir, -1).DetectChanges(context.Background())
require.NoError(t, err)
require.Empty(t, base)
require.Equal(t, files, feat)
base, feat, err = migratelint.LatestChanges(dir, 1).DetectChanges(context.Background())
require.NoError(t, err)
require.Equal(t, files[:1], base)
require.Equal(t, files[1:], feat)
}
================================================
FILE: cmd/atlas/internal/sqlparse/myparse/myparse_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package myparse
import (
"errors"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
)
// Parser for fixing linting changes.
type FileParser struct{}
// FixChange fixes the changes according to the given statement.
func (*FileParser) FixChange(migrate.Driver, string, schema.Changes) (schema.Changes, error) {
return nil, errors.New("unimplemented")
}
// ColumnFilledBefore checks if the column was filled with values before the given position in the file.
func (*FileParser) ColumnFilledBefore([]*migrate.Stmt, *schema.Table, *schema.Column, int) (bool, error) {
return false, errors.New("unimplemented")
}
// CreateViewAfter checks if a view was created after the position with the given name to a table.
func (*FileParser) CreateViewAfter([]*migrate.Stmt, string, string, int) (bool, error) {
return false, errors.New("unimplemented")
}
================================================
FILE: cmd/atlas/internal/sqlparse/parseutil/parseutil.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Package parseutil exposes shared functions used by the different parsers.
package parseutil
import (
"slices"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
)
// Rename describes rename of a resource.
type Rename struct {
From, To string
}
// RenameColumn patches DROP/ADD column commands to RENAME.
func RenameColumn(modify *schema.ModifyTable, r *Rename) {
changes := schema.Changes(modify.Changes)
switch i, j := changes.IndexDropColumn(r.From), changes.IndexAddColumn(r.To); {
case j == -1:
// Rename column.
case i != -1:
changes[max(i, j)] = &schema.RenameColumn{
From: changes[i].(*schema.DropColumn).C,
To: changes[j].(*schema.AddColumn).C,
}
changes.RemoveIndex(min(i, j))
// Rename column and add the previous name back.
default:
if i = changes.IndexModifyColumn(r.From); i == -1 {
// ADD COLUMN must come after the RENAME.
return
}
modify := changes[i].(*schema.ModifyColumn)
changes[min(i, j)] = &schema.RenameColumn{
From: modify.From,
To: changes[j].(*schema.AddColumn).C,
}
changes[max(i, j)] = &schema.AddColumn{
C: modify.To,
}
}
modify.Changes = changes
}
// RenameIndex patches DROP/ADD index commands to RENAME.
func RenameIndex(modify *schema.ModifyTable, r *Rename) {
changes := schema.Changes(modify.Changes)
i := changes.IndexDropIndex(r.From)
j := changes.IndexAddIndex(r.To)
if i != -1 && j != -1 {
changes[max(i, j)] = &schema.RenameIndex{
From: changes[i].(*schema.DropIndex).I,
To: changes[j].(*schema.AddIndex).I,
}
changes.RemoveIndex(min(i, j))
modify.Changes = changes
}
}
// RenameTable patches DROP/ADD table commands to RENAME.
func RenameTable(changes schema.Changes, r *Rename) schema.Changes {
i := changes.LastIndexDropTable(r.From)
j := changes.LastIndexAddTable(r.To)
if i != -1 && j != -1 {
changes[max(i, j)] = &schema.RenameTable{
From: changes[i].(*schema.DropTable).T,
To: changes[j].(*schema.AddTable).T,
}
changes.RemoveIndex(min(i, j))
}
return changes
}
// MatchStmtBefore reports if the file contains any statement that matches the predicate before the given position.
func MatchStmtBefore(stmts []*migrate.Stmt, pos int, p func(*migrate.Stmt) (bool, error)) (bool, error) {
i := slices.IndexFunc(stmts, func(s *migrate.Stmt) bool {
return s.Pos >= pos
})
if i != -1 {
stmts = stmts[:i]
}
for _, s := range stmts {
m, err := p(s)
if err != nil {
return false, err
}
if m {
return true, nil
}
}
return false, nil
}
// MatchStmtAfter reports if the file contains any statement that matches the predicate after the given position.
func MatchStmtAfter(stmts []*migrate.Stmt, pos int, p func(*migrate.Stmt) (bool, error)) (bool, error) {
i := slices.IndexFunc(stmts, func(s *migrate.Stmt) bool {
return s.Pos > pos
})
if i == -1 {
return false, nil
}
stmts = stmts[i:]
for _, s := range stmts {
m, err := p(s)
if err != nil {
return false, err
}
if m {
return true, nil
}
}
return false, nil
}
================================================
FILE: cmd/atlas/internal/sqlparse/pgparse/pgparse_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package pgparse
import (
"errors"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
)
type Parser struct{}
func (*Parser) ColumnFilledBefore([]*migrate.Stmt, *schema.Table, *schema.Column, int) (bool, error) {
return false, errors.New("unimplemented")
}
func (*Parser) CreateViewAfter([]*migrate.Stmt, string, string, int) (bool, error) {
return false, errors.New("unimplemented")
}
func (*Parser) FixChange(_ migrate.Driver, _ string, changes schema.Changes) (schema.Changes, error) {
return changes, nil // Unimplemented.
}
================================================
FILE: cmd/atlas/internal/sqlparse/sqliteparse/Lexer.g4
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 by Martin Mirchev
*
* 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.
*
* Project : sqlite-parser; an ANTLR4 grammar for SQLite https://github.com/bkiers/sqlite-parser
* Developed by : Bart Kiers, bart@big-o.nl
*/
// $antlr-format alignTrailingComments on, columnLimit 150, maxEmptyLinesToKeep 1, reflowComments off, useTab off
// $antlr-format allowShortRulesOnASingleLine on, alignSemicolons ownLine
lexer grammar Lexer;
options { caseInsensitive = true; }
SCOL: ';';
DOT: '.';
OPEN_PAR: '(';
CLOSE_PAR: ')';
COMMA: ',';
ASSIGN: '=';
STAR: '*';
PLUS: '+';
MINUS: '-';
TILDE: '~';
PIPE2: '||';
DIV: '/';
MOD: '%';
LT2: '<<';
GT2: '>>';
AMP: '&';
PIPE: '|';
LT: '<';
LT_EQ: '<=';
GT: '>';
GT_EQ: '>=';
EQ: '==';
NOT_EQ1: '!=';
NOT_EQ2: '<>';
// http://www.sqlite.org/lang_keywords.html
ABORT_: 'ABORT';
ACTION_: 'ACTION';
ADD_: 'ADD';
AFTER_: 'AFTER';
ALL_: 'ALL';
ALTER_: 'ALTER';
ANALYZE_: 'ANALYZE';
AND_: 'AND';
AS_: 'AS';
ASC_: 'ASC';
ATTACH_: 'ATTACH';
AUTOINCREMENT_: 'AUTOINCREMENT';
BEFORE_: 'BEFORE';
BEGIN_: 'BEGIN';
BETWEEN_: 'BETWEEN';
BY_: 'BY';
CASCADE_: 'CASCADE';
CASE_: 'CASE';
CAST_: 'CAST';
CHECK_: 'CHECK';
COLLATE_: 'COLLATE';
COLUMN_: 'COLUMN';
COMMIT_: 'COMMIT';
CONFLICT_: 'CONFLICT';
CONSTRAINT_: 'CONSTRAINT';
CREATE_: 'CREATE';
CROSS_: 'CROSS';
CURRENT_DATE_: 'CURRENT_DATE';
CURRENT_TIME_: 'CURRENT_TIME';
CURRENT_TIMESTAMP_: 'CURRENT_TIMESTAMP';
DATABASE_: 'DATABASE';
DEFAULT_: 'DEFAULT';
DEFERRABLE_: 'DEFERRABLE';
DEFERRED_: 'DEFERRED';
DELETE_: 'DELETE';
DESC_: 'DESC';
DETACH_: 'DETACH';
DISTINCT_: 'DISTINCT';
DROP_: 'DROP';
EACH_: 'EACH';
ELSE_: 'ELSE';
END_: 'END';
ESCAPE_: 'ESCAPE';
EXCEPT_: 'EXCEPT';
EXCLUSIVE_: 'EXCLUSIVE';
EXISTS_: 'EXISTS';
EXPLAIN_: 'EXPLAIN';
FAIL_: 'FAIL';
FOR_: 'FOR';
FOREIGN_: 'FOREIGN';
FROM_: 'FROM';
FULL_: 'FULL';
GLOB_: 'GLOB';
GROUP_: 'GROUP';
HAVING_: 'HAVING';
IF_: 'IF';
IGNORE_: 'IGNORE';
IMMEDIATE_: 'IMMEDIATE';
IN_: 'IN';
INDEX_: 'INDEX';
INDEXED_: 'INDEXED';
INITIALLY_: 'INITIALLY';
INNER_: 'INNER';
INSERT_: 'INSERT';
INSTEAD_: 'INSTEAD';
INTERSECT_: 'INTERSECT';
INTO_: 'INTO';
IS_: 'IS';
ISNULL_: 'ISNULL';
JOIN_: 'JOIN';
KEY_: 'KEY';
LEFT_: 'LEFT';
LIKE_: 'LIKE';
LIMIT_: 'LIMIT';
MATCH_: 'MATCH';
NATURAL_: 'NATURAL';
NO_: 'NO';
NOT_: 'NOT';
NOTNULL_: 'NOTNULL';
NULL_: 'NULL';
OF_: 'OF';
OFFSET_: 'OFFSET';
ON_: 'ON';
OR_: 'OR';
ORDER_: 'ORDER';
OUTER_: 'OUTER';
PLAN_: 'PLAN';
PRAGMA_: 'PRAGMA';
PRIMARY_: 'PRIMARY';
QUERY_: 'QUERY';
RAISE_: 'RAISE';
RECURSIVE_: 'RECURSIVE';
REFERENCES_: 'REFERENCES';
REGEXP_: 'REGEXP';
REINDEX_: 'REINDEX';
RELEASE_: 'RELEASE';
RENAME_: 'RENAME';
REPLACE_: 'REPLACE';
RESTRICT_: 'RESTRICT';
RETURNING_: 'RETURNING';
RIGHT_: 'RIGHT';
ROLLBACK_: 'ROLLBACK';
ROW_: 'ROW';
ROWS_: 'ROWS';
SAVEPOINT_: 'SAVEPOINT';
SELECT_: 'SELECT';
SET_: 'SET';
TABLE_: 'TABLE';
TEMP_: 'TEMP';
TEMPORARY_: 'TEMPORARY';
THEN_: 'THEN';
TO_: 'TO';
TRANSACTION_: 'TRANSACTION';
TRIGGER_: 'TRIGGER';
UNION_: 'UNION';
UNIQUE_: 'UNIQUE';
UPDATE_: 'UPDATE';
USING_: 'USING';
VACUUM_: 'VACUUM';
VALUES_: 'VALUES';
VIEW_: 'VIEW';
VIRTUAL_: 'VIRTUAL';
WHEN_: 'WHEN';
WHERE_: 'WHERE';
WITH_: 'WITH';
WITHOUT_: 'WITHOUT';
FIRST_VALUE_: 'FIRST_VALUE';
OVER_: 'OVER';
PARTITION_: 'PARTITION';
RANGE_: 'RANGE';
PRECEDING_: 'PRECEDING';
UNBOUNDED_: 'UNBOUNDED';
CURRENT_: 'CURRENT';
FOLLOWING_: 'FOLLOWING';
CUME_DIST_: 'CUME_DIST';
DENSE_RANK_: 'DENSE_RANK';
LAG_: 'LAG';
LAST_VALUE_: 'LAST_VALUE';
LEAD_: 'LEAD';
NTH_VALUE_: 'NTH_VALUE';
NTILE_: 'NTILE';
PERCENT_RANK_: 'PERCENT_RANK';
RANK_: 'RANK';
ROW_NUMBER_: 'ROW_NUMBER';
GENERATED_: 'GENERATED';
ALWAYS_: 'ALWAYS';
STORED_: 'STORED';
TRUE_: 'TRUE';
FALSE_: 'FALSE';
WINDOW_: 'WINDOW';
NULLS_: 'NULLS';
FIRST_: 'FIRST';
LAST_: 'LAST';
FILTER_: 'FILTER';
GROUPS_: 'GROUPS';
EXCLUDE_: 'EXCLUDE';
TIES_: 'TIES';
OTHERS_: 'OTHERS';
DO_: 'DO';
NOTHING_: 'NOTHING';
IDENTIFIER:
'"' (~'"' | '""')* '"'
| '`' (~'`' | '``')* '`'
| '[' ~']'* ']'
| [A-Z_] [A-Z_0-9]*
; // TODO check: needs more chars in set
NUMERIC_LITERAL: ((DIGIT+ ('.' DIGIT*)?) | ('.' DIGIT+)) ('E' [-+]? DIGIT+)? | '0x' HEX_DIGIT+;
BIND_PARAMETER: '?' DIGIT* | [:@$] IDENTIFIER;
STRING_LITERAL: '\'' ( ~'\'' | '\'\'')* '\'';
BLOB_LITERAL: 'X' STRING_LITERAL;
SINGLE_LINE_COMMENT: '--' ~[\r\n]* (('\r'? '\n') | EOF) -> channel(HIDDEN);
MULTILINE_COMMENT: '/*' .*? '*/' -> channel(HIDDEN);
SPACES: [ \u000B\t\r\n] -> channel(HIDDEN);
UNEXPECTED_CHAR: .;
fragment HEX_DIGIT: [0-9A-F];
fragment DIGIT: [0-9];
================================================
FILE: cmd/atlas/internal/sqlparse/sqliteparse/Parser.g4
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2014 by Bart Kiers
*
* 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.
*
* Project : sqlite-parser; an ANTLR4 grammar for SQLite https://github.com/bkiers/sqlite-parser
* Developed by:
* Bart Kiers, bart@big-o.nl
* Martin Mirchev, marti_2203@abv.bg
* Mike Lische, mike@lischke-online.de
*/
// $antlr-format alignTrailingComments on, columnLimit 130, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments off
// $antlr-format useTab off, allowShortRulesOnASingleLine off, allowShortBlocksOnASingleLine on, alignSemicolons ownLine
parser grammar Parser;
options {
tokenVocab = Lexer;
}
parse: (sql_stmt_list)* EOF
;
sql_stmt_list:
SCOL* sql_stmt (SCOL+ sql_stmt)* SCOL*
;
sql_stmt: (EXPLAIN_ (QUERY_ PLAN_)?)? (
alter_table_stmt
| analyze_stmt
| attach_stmt
| begin_stmt
| commit_stmt
| create_index_stmt
| create_table_stmt
| create_trigger_stmt
| create_view_stmt
| create_virtual_table_stmt
| delete_stmt
| delete_stmt_limited
| detach_stmt
| drop_stmt
| insert_stmt
| pragma_stmt
| reindex_stmt
| release_stmt
| rollback_stmt
| savepoint_stmt
| select_stmt
| update_stmt
| update_stmt_limited
| vacuum_stmt
)
;
alter_table_stmt:
ALTER_ TABLE_ (schema_name DOT)? table_name (
RENAME_ (
TO_ new_table_name = table_name
| COLUMN_? old_column_name = column_name TO_ new_column_name = column_name
)
| ADD_ COLUMN_? column_def
| DROP_ COLUMN_? column_name
)
;
analyze_stmt:
ANALYZE_ (schema_name | (schema_name DOT)? table_or_index_name)?
;
attach_stmt:
ATTACH_ DATABASE_? expr AS_ schema_name
;
begin_stmt:
BEGIN_ (DEFERRED_ | IMMEDIATE_ | EXCLUSIVE_)? (
TRANSACTION_ transaction_name?
)?
;
commit_stmt: (COMMIT_ | END_) TRANSACTION_?
;
rollback_stmt:
ROLLBACK_ TRANSACTION_? (TO_ SAVEPOINT_? savepoint_name)?
;
savepoint_stmt:
SAVEPOINT_ savepoint_name
;
release_stmt:
RELEASE_ SAVEPOINT_? savepoint_name
;
create_index_stmt:
CREATE_ UNIQUE_? INDEX_ (IF_ NOT_ EXISTS_)? (schema_name DOT)? index_name ON_ table_name OPEN_PAR
indexed_column (COMMA indexed_column)* CLOSE_PAR (WHERE_ expr)?
;
indexed_column: (column_name | expr) (COLLATE_ collation_name)? asc_desc?
;
create_table_stmt:
CREATE_ (TEMP_ | TEMPORARY_)? TABLE_ (IF_ NOT_ EXISTS_)? (
schema_name DOT
)? table_name (
OPEN_PAR column_def (COMMA column_def)*? (COMMA table_constraint)* CLOSE_PAR (
WITHOUT_ row_ROW_ID = IDENTIFIER
)?
| AS_ select_stmt
)
;
column_def:
column_name type_name? column_constraint*
;
type_name:
name+? (
OPEN_PAR signed_number CLOSE_PAR
| OPEN_PAR signed_number COMMA signed_number CLOSE_PAR
)?
;
column_constraint: (CONSTRAINT_ name)? (
(PRIMARY_ KEY_ asc_desc? conflict_clause? AUTOINCREMENT_?)
| (NOT_ NULL_ | UNIQUE_) conflict_clause?
| CHECK_ OPEN_PAR expr CLOSE_PAR
| DEFAULT_ (signed_number | literal_value | OPEN_PAR expr CLOSE_PAR)
| COLLATE_ collation_name
| foreign_key_clause
| (GENERATED_ ALWAYS_)? AS_ OPEN_PAR expr CLOSE_PAR (
STORED_
| VIRTUAL_
)?
)
;
signed_number: (PLUS | MINUS)? NUMERIC_LITERAL
;
table_constraint: (CONSTRAINT_ name)? (
(PRIMARY_ KEY_ | UNIQUE_) OPEN_PAR indexed_column (
COMMA indexed_column
)* CLOSE_PAR conflict_clause?
| CHECK_ OPEN_PAR expr CLOSE_PAR
| FOREIGN_ KEY_ OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR foreign_key_clause
)
;
foreign_key_clause:
REFERENCES_ foreign_table (
OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR
)? (
ON_ (DELETE_ | UPDATE_) (
SET_ (NULL_ | DEFAULT_)
| CASCADE_
| RESTRICT_
| NO_ ACTION_
)
| MATCH_ name
)* (NOT_? DEFERRABLE_ (INITIALLY_ (DEFERRED_ | IMMEDIATE_))?)?
;
conflict_clause:
ON_ CONFLICT_ (
ROLLBACK_
| ABORT_
| FAIL_
| IGNORE_
| REPLACE_
)
;
create_trigger_stmt:
CREATE_ (TEMP_ | TEMPORARY_)? TRIGGER_ (IF_ NOT_ EXISTS_)? (
schema_name DOT
)? trigger_name (BEFORE_ | AFTER_ | INSTEAD_ OF_)? (
DELETE_
| INSERT_
| UPDATE_ (OF_ column_name ( COMMA column_name)*)?
) ON_ table_name (FOR_ EACH_ ROW_)? (WHEN_ expr)? BEGIN_ (
(update_stmt | insert_stmt | delete_stmt | select_stmt) SCOL
)+ END_
;
create_view_stmt:
CREATE_ (TEMP_ | TEMPORARY_)? VIEW_ (IF_ NOT_ EXISTS_)? (
schema_name DOT
)? view_name (OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR)? AS_ select_stmt
;
create_virtual_table_stmt:
CREATE_ VIRTUAL_ TABLE_ (IF_ NOT_ EXISTS_)? (schema_name DOT)? table_name USING_ module_name (
OPEN_PAR module_argument (COMMA module_argument)* CLOSE_PAR
)?
;
with_clause:
WITH_ RECURSIVE_? cte_table_name AS_ OPEN_PAR select_stmt CLOSE_PAR (
COMMA cte_table_name AS_ OPEN_PAR select_stmt CLOSE_PAR
)*
;
cte_table_name:
table_name (OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR)?
;
recursive_cte:
cte_table_name AS_ OPEN_PAR initial_select UNION_ ALL_? recursive_select CLOSE_PAR
;
common_table_expression:
table_name (OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR)? AS_ OPEN_PAR select_stmt CLOSE_PAR
;
delete_stmt:
with_clause? DELETE_ FROM_ qualified_table_name (WHERE_ expr)? returning_clause?
;
delete_stmt_limited:
with_clause? DELETE_ FROM_ qualified_table_name (WHERE_ expr)? returning_clause? (
order_by_stmt? limit_stmt
)?
;
detach_stmt:
DETACH_ DATABASE_? schema_name
;
drop_stmt:
DROP_ object = (INDEX_ | TABLE_ | TRIGGER_ | VIEW_) (
IF_ EXISTS_
)? (schema_name DOT)? any_name
;
/*
SQLite understands the following binary operators, in order from highest to lowest precedence:
||
* / %
+ -
<< >> & |
< <= > >=
= == != <> IS IS NOT IN LIKE GLOB MATCH REGEXP
AND
OR
*/
expr:
literal_value
| BIND_PARAMETER
| ((schema_name DOT)? table_name DOT)? column_name
| unary_operator expr
| expr PIPE2 expr
| expr ( STAR | DIV | MOD) expr
| expr ( PLUS | MINUS) expr
| expr ( LT2 | GT2 | AMP | PIPE) expr
| expr ( LT | LT_EQ | GT | GT_EQ) expr
| expr (
ASSIGN
| EQ
| NOT_EQ1
| NOT_EQ2
| IS_
| IS_ NOT_
| IN_
| LIKE_
| GLOB_
| MATCH_
| REGEXP_
) expr
| expr AND_ expr
| expr OR_ expr
| function_name OPEN_PAR ((DISTINCT_? expr ( COMMA expr)*) | STAR)? CLOSE_PAR filter_clause? over_clause?
| OPEN_PAR expr (COMMA expr)* CLOSE_PAR
| CAST_ OPEN_PAR expr AS_ type_name CLOSE_PAR
| expr COLLATE_ collation_name
| expr NOT_? (LIKE_ | GLOB_ | REGEXP_ | MATCH_) expr (
ESCAPE_ expr
)?
| expr ( ISNULL_ | NOTNULL_ | NOT_ NULL_)
| expr IS_ NOT_? expr
| expr NOT_? BETWEEN_ expr AND_ expr
| expr NOT_? IN_ (
OPEN_PAR (select_stmt | expr ( COMMA expr)*)? CLOSE_PAR
| ( schema_name DOT)? table_name
| (schema_name DOT)? table_function_name OPEN_PAR (expr (COMMA expr)*)? CLOSE_PAR
)
| ((NOT_)? EXISTS_)? OPEN_PAR select_stmt CLOSE_PAR
| CASE_ expr? (WHEN_ expr THEN_ expr)+ (ELSE_ expr)? END_
| raise_function
;
raise_function:
RAISE_ OPEN_PAR (
IGNORE_
| (ROLLBACK_ | ABORT_ | FAIL_) COMMA error_message
) CLOSE_PAR
;
literal_value:
NUMERIC_LITERAL
| STRING_LITERAL
| BLOB_LITERAL
| NULL_
| TRUE_
| FALSE_
| CURRENT_TIME_
| CURRENT_DATE_
| CURRENT_TIMESTAMP_
;
insert_stmt:
with_clause? (
INSERT_
| REPLACE_
| INSERT_ OR_ (
REPLACE_
| ROLLBACK_
| ABORT_
| FAIL_
| IGNORE_
)
) INTO_ (schema_name DOT)? table_name (AS_ table_alias)? (
OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR
)? (
(
(
VALUES_ OPEN_PAR expr (COMMA expr)* CLOSE_PAR (
COMMA OPEN_PAR expr ( COMMA expr)* CLOSE_PAR
)*
| select_stmt
) upsert_clause?
)
| DEFAULT_ VALUES_
) returning_clause?
;
returning_clause:
RETURNING_ result_column (COMMA result_column)*
;
upsert_clause:
ON_ CONFLICT_ (
OPEN_PAR indexed_column (COMMA indexed_column)* CLOSE_PAR (WHERE_ expr)?
)? DO_ (
NOTHING_
| UPDATE_ SET_ (
(column_name | column_name_list) ASSIGN expr (
COMMA (column_name | column_name_list) ASSIGN expr
)* (WHERE_ expr)?
)
)
;
pragma_stmt:
PRAGMA_ (schema_name DOT)? pragma_name (
ASSIGN pragma_value
| OPEN_PAR pragma_value CLOSE_PAR
)?
;
pragma_value:
signed_number
| name
| STRING_LITERAL
;
reindex_stmt:
REINDEX_ (collation_name | (schema_name DOT)? (table_name | index_name))?
;
select_stmt:
common_table_stmt? select_core (compound_operator select_core)* order_by_stmt? limit_stmt?
;
join_clause:
table_or_subquery (join_operator table_or_subquery join_constraint?)*
;
select_core:
(
SELECT_ (DISTINCT_ | ALL_)? result_column (COMMA result_column)* (
FROM_ (table_or_subquery (COMMA table_or_subquery)* | join_clause)
)? (WHERE_ expr)? (GROUP_ BY_ expr (COMMA expr)* (HAVING_ expr)?)? (
WINDOW_ window_name AS_ window_defn (
COMMA window_name AS_ window_defn
)*
)?
)
| VALUES_ OPEN_PAR expr (COMMA expr)* CLOSE_PAR (
COMMA OPEN_PAR expr ( COMMA expr)* CLOSE_PAR
)*
;
factored_select_stmt:
select_stmt
;
simple_select_stmt:
common_table_stmt? select_core order_by_stmt? limit_stmt?
;
compound_select_stmt:
common_table_stmt? select_core (
(UNION_ ALL_? | INTERSECT_ | EXCEPT_) select_core
)+ order_by_stmt? limit_stmt?
;
table_or_subquery: (
(schema_name DOT)? table_name (AS_? table_alias)? (
INDEXED_ BY_ index_name
| NOT_ INDEXED_
)?
)
| (schema_name DOT)? table_function_name OPEN_PAR expr (COMMA expr)* CLOSE_PAR (
AS_? table_alias
)?
| OPEN_PAR (table_or_subquery (COMMA table_or_subquery)* | join_clause) CLOSE_PAR
| OPEN_PAR select_stmt CLOSE_PAR (AS_? table_alias)?
;
result_column:
STAR
| table_name DOT STAR
| expr ( AS_? column_alias)?
;
join_operator:
COMMA
| NATURAL_? (LEFT_ OUTER_? | INNER_ | CROSS_)? JOIN_
;
join_constraint:
ON_ expr
| USING_ OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR
;
compound_operator:
UNION_ ALL_?
| INTERSECT_
| EXCEPT_
;
update_stmt:
with_clause? UPDATE_ (
OR_ (ROLLBACK_ | ABORT_ | REPLACE_ | FAIL_ | IGNORE_)
)? qualified_table_name SET_ assignment_list (
FROM_ (table_or_subquery (COMMA table_or_subquery)* | join_clause)
)? (WHERE_ where = expr)? returning_clause?
;
assignment_list:
assignment
(COMMA assignment)*
;
assignment:
(column_name | column_name_list) ASSIGN expr
;
column_name_list:
OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR
;
update_stmt_limited:
with_clause? UPDATE_ (
OR_ (ROLLBACK_ | ABORT_ | REPLACE_ | FAIL_ | IGNORE_)
)? qualified_table_name SET_ (column_name | column_name_list) ASSIGN expr (
COMMA (column_name | column_name_list) ASSIGN expr
)* (WHERE_ expr)? returning_clause? (order_by_stmt? limit_stmt)?
;
qualified_table_name: (schema_name DOT)? table_name (AS_ alias)? (
INDEXED_ BY_ index_name
| NOT_ INDEXED_
)?
;
vacuum_stmt:
VACUUM_ schema_name? (INTO_ filename)?
;
filter_clause:
FILTER_ OPEN_PAR WHERE_ expr CLOSE_PAR
;
window_defn:
OPEN_PAR base_window_name? (PARTITION_ BY_ expr (COMMA expr)*)? (
ORDER_ BY_ ordering_term (COMMA ordering_term)*
) frame_spec? CLOSE_PAR
;
over_clause:
OVER_ (
window_name
| OPEN_PAR base_window_name? (PARTITION_ BY_ expr (COMMA expr)*)? (
ORDER_ BY_ ordering_term (COMMA ordering_term)*
)? frame_spec? CLOSE_PAR
)
;
frame_spec:
frame_clause (
EXCLUDE_ (NO_ OTHERS_)
| CURRENT_ ROW_
| GROUP_
| TIES_
)?
;
frame_clause: (RANGE_ | ROWS_ | GROUPS_) (
frame_single
| BETWEEN_ frame_left AND_ frame_right
)
;
simple_function_invocation:
simple_func OPEN_PAR (expr (COMMA expr)* | STAR) CLOSE_PAR
;
aggregate_function_invocation:
aggregate_func OPEN_PAR (DISTINCT_? expr (COMMA expr)* | STAR)? CLOSE_PAR filter_clause?
;
window_function_invocation:
window_function OPEN_PAR (expr (COMMA expr)* | STAR)? CLOSE_PAR filter_clause? OVER_ (
window_defn
| window_name
)
;
common_table_stmt: //additional structures
WITH_ RECURSIVE_? common_table_expression (COMMA common_table_expression)*
;
order_by_stmt:
ORDER_ BY_ ordering_term (COMMA ordering_term)*
;
limit_stmt:
LIMIT_ expr ((OFFSET_ | COMMA) expr)?
;
ordering_term:
expr (COLLATE_ collation_name)? asc_desc? (NULLS_ (FIRST_ | LAST_))?
;
asc_desc:
ASC_
| DESC_
;
frame_left:
expr PRECEDING_
| expr FOLLOWING_
| CURRENT_ ROW_
| UNBOUNDED_ PRECEDING_
;
frame_right:
expr PRECEDING_
| expr FOLLOWING_
| CURRENT_ ROW_
| UNBOUNDED_ FOLLOWING_
;
frame_single:
expr PRECEDING_
| UNBOUNDED_ PRECEDING_
| CURRENT_ ROW_
;
// unknown
window_function:
(FIRST_VALUE_ | LAST_VALUE_) OPEN_PAR expr CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc frame_clause
? CLOSE_PAR
| (CUME_DIST_ | PERCENT_RANK_) OPEN_PAR CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr? CLOSE_PAR
| (DENSE_RANK_ | RANK_ | ROW_NUMBER_) OPEN_PAR CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc
CLOSE_PAR
| (LAG_ | LEAD_) OPEN_PAR expr offset? default_value? CLOSE_PAR OVER_ OPEN_PAR partition_by?
order_by_expr_asc_desc CLOSE_PAR
| NTH_VALUE_ OPEN_PAR expr COMMA signed_number CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc
frame_clause? CLOSE_PAR
| NTILE_ OPEN_PAR expr CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc CLOSE_PAR
;
offset:
COMMA signed_number
;
default_value:
COMMA signed_number
;
partition_by:
PARTITION_ BY_ expr+
;
order_by_expr:
ORDER_ BY_ expr+
;
order_by_expr_asc_desc:
ORDER_ BY_ expr_asc_desc
;
expr_asc_desc:
expr asc_desc? (COMMA expr asc_desc?)*
;
//TODO BOTH OF THESE HAVE TO BE REWORKED TO FOLLOW THE SPEC
initial_select:
select_stmt
;
recursive_select:
select_stmt
;
unary_operator:
MINUS
| PLUS
| TILDE
| NOT_
;
error_message:
STRING_LITERAL
;
module_argument: // TODO check what exactly is permitted here
expr
| column_def
;
column_alias:
IDENTIFIER
| STRING_LITERAL
;
keyword:
ABORT_
| ACTION_
| ADD_
| AFTER_
| ALL_
| ALTER_
| ANALYZE_
| AND_
| AS_
| ASC_
| ATTACH_
| AUTOINCREMENT_
| BEFORE_
| BEGIN_
| BETWEEN_
| BY_
| CASCADE_
| CASE_
| CAST_
| CHECK_
| COLLATE_
| COLUMN_
| COMMIT_
| CONFLICT_
| CONSTRAINT_
| CREATE_
| CROSS_
| CURRENT_DATE_
| CURRENT_TIME_
| CURRENT_TIMESTAMP_
| DATABASE_
| DEFAULT_
| DEFERRABLE_
| DEFERRED_
| DELETE_
| DESC_
| DETACH_
| DISTINCT_
| DROP_
| EACH_
| ELSE_
| END_
| ESCAPE_
| EXCEPT_
| EXCLUSIVE_
| EXISTS_
| EXPLAIN_
| FAIL_
| FOR_
| FOREIGN_
| FROM_
| FULL_
| GLOB_
| GROUP_
| HAVING_
| IF_
| IGNORE_
| IMMEDIATE_
| IN_
| INDEX_
| INDEXED_
| INITIALLY_
| INNER_
| INSERT_
| INSTEAD_
| INTERSECT_
| INTO_
| IS_
| ISNULL_
| JOIN_
| KEY_
| LEFT_
| LIKE_
| LIMIT_
| MATCH_
| NATURAL_
| NO_
| NOT_
| NOTNULL_
| NULL_
| OF_
| OFFSET_
| ON_
| OR_
| ORDER_
| OUTER_
| PLAN_
| PRAGMA_
| PRIMARY_
| QUERY_
| RAISE_
| RECURSIVE_
| REFERENCES_
| REGEXP_
| REINDEX_
| RELEASE_
| RENAME_
| REPLACE_
| RESTRICT_
| RIGHT_
| ROLLBACK_
| ROW_
| ROWS_
| SAVEPOINT_
| SELECT_
| SET_
| TABLE_
| TEMP_
| TEMPORARY_
| THEN_
| TO_
| TRANSACTION_
| TRIGGER_
| UNION_
| UNIQUE_
| UPDATE_
| USING_
| VACUUM_
| VALUES_
| VIEW_
| VIRTUAL_
| WHEN_
| WHERE_
| WITH_
| WITHOUT_
| FIRST_VALUE_
| OVER_
| PARTITION_
| RANGE_
| PRECEDING_
| UNBOUNDED_
| CURRENT_
| FOLLOWING_
| CUME_DIST_
| DENSE_RANK_
| LAG_
| LAST_VALUE_
| LEAD_
| NTH_VALUE_
| NTILE_
| PERCENT_RANK_
| RANK_
| ROW_NUMBER_
| GENERATED_
| ALWAYS_
| STORED_
| TRUE_
| FALSE_
| WINDOW_
| NULLS_
| FIRST_
| LAST_
| FILTER_
| GROUPS_
| EXCLUDE_
;
// TODO: check all names below
name:
any_name
;
function_name:
any_name
;
schema_name:
any_name
;
table_name:
any_name
;
table_or_index_name:
any_name
;
column_name:
any_name
;
collation_name:
any_name
;
foreign_table:
any_name
;
index_name:
any_name
;
trigger_name:
any_name
;
view_name:
any_name
;
module_name:
any_name
;
pragma_name:
any_name
;
savepoint_name:
any_name
;
table_alias:
any_name
;
transaction_name:
any_name
;
window_name:
any_name
;
alias:
any_name
;
filename:
any_name
;
base_window_name:
any_name
;
simple_func:
any_name
;
aggregate_func:
any_name
;
table_function_name:
any_name
;
any_name:
IDENTIFIER
| keyword
| STRING_LITERAL
| OPEN_PAR any_name CLOSE_PAR
;
================================================
FILE: cmd/atlas/internal/sqlparse/sqliteparse/README.md
================================================
### SQLite parser based on ANTLR4
#### Resources
1. SQLite syntax: https://www.sqlite.org/syntaxdiagrams.html
2. Grammar file: https://github.com/antlr/grammars-v4/tree/master/sql/sqlite
#### Run codegen
1. Install `antlr4`: https://github.com/antlr/antlr4/blob/master/doc/getting-started.md#unix
2. Run:
```bash
antlr4 -Dlanguage=Go -package sqliteparse -visitor Lexer.g4 Parser.g4 \
&& mv _lexer.go lexer.go \
&& mv _parser.go parser.go \
&& rm *.interp *.tokens
```
================================================
FILE: cmd/atlas/internal/sqlparse/sqliteparse/lexer.go
================================================
// Code generated from Lexer.g4 by ANTLR 4.13.1. DO NOT EDIT.
package sqliteparse
import (
"fmt"
"github.com/antlr4-go/antlr/v4"
"sync"
"unicode"
)
// Suppress unused import error
var _ = fmt.Printf
var _ = sync.Once{}
var _ = unicode.IsLetter
type Lexer struct {
*antlr.BaseLexer
channelNames []string
modeNames []string
// TODO: EOF string
}
var LexerLexerStaticData struct {
once sync.Once
serializedATN []int32
ChannelNames []string
ModeNames []string
LiteralNames []string
SymbolicNames []string
RuleNames []string
PredictionContextCache *antlr.PredictionContextCache
atn *antlr.ATN
decisionToDFA []*antlr.DFA
}
func lexerLexerInit() {
staticData := &LexerLexerStaticData
staticData.ChannelNames = []string{
"DEFAULT_TOKEN_CHANNEL", "HIDDEN",
}
staticData.ModeNames = []string{
"DEFAULT_MODE",
}
staticData.LiteralNames = []string{
"", "';'", "'.'", "'('", "')'", "','", "'='", "'*'", "'+'", "'-'", "'~'",
"'||'", "'/'", "'%'", "'<<'", "'>>'", "'&'", "'|'", "'<'", "'<='", "'>'",
"'>='", "'=='", "'!='", "'<>'", "'ABORT'", "'ACTION'", "'ADD'", "'AFTER'",
"'ALL'", "'ALTER'", "'ANALYZE'", "'AND'", "'AS'", "'ASC'", "'ATTACH'",
"'AUTOINCREMENT'", "'BEFORE'", "'BEGIN'", "'BETWEEN'", "'BY'", "'CASCADE'",
"'CASE'", "'CAST'", "'CHECK'", "'COLLATE'", "'COLUMN'", "'COMMIT'",
"'CONFLICT'", "'CONSTRAINT'", "'CREATE'", "'CROSS'", "'CURRENT_DATE'",
"'CURRENT_TIME'", "'CURRENT_TIMESTAMP'", "'DATABASE'", "'DEFAULT'",
"'DEFERRABLE'", "'DEFERRED'", "'DELETE'", "'DESC'", "'DETACH'", "'DISTINCT'",
"'DROP'", "'EACH'", "'ELSE'", "'END'", "'ESCAPE'", "'EXCEPT'", "'EXCLUSIVE'",
"'EXISTS'", "'EXPLAIN'", "'FAIL'", "'FOR'", "'FOREIGN'", "'FROM'", "'FULL'",
"'GLOB'", "'GROUP'", "'HAVING'", "'IF'", "'IGNORE'", "'IMMEDIATE'",
"'IN'", "'INDEX'", "'INDEXED'", "'INITIALLY'", "'INNER'", "'INSERT'",
"'INSTEAD'", "'INTERSECT'", "'INTO'", "'IS'", "'ISNULL'", "'JOIN'",
"'KEY'", "'LEFT'", "'LIKE'", "'LIMIT'", "'MATCH'", "'NATURAL'", "'NO'",
"'NOT'", "'NOTNULL'", "'NULL'", "'OF'", "'OFFSET'", "'ON'", "'OR'",
"'ORDER'", "'OUTER'", "'PLAN'", "'PRAGMA'", "'PRIMARY'", "'QUERY'",
"'RAISE'", "'RECURSIVE'", "'REFERENCES'", "'REGEXP'", "'REINDEX'", "'RELEASE'",
"'RENAME'", "'REPLACE'", "'RESTRICT'", "'RETURNING'", "'RIGHT'", "'ROLLBACK'",
"'ROW'", "'ROWS'", "'SAVEPOINT'", "'SELECT'", "'SET'", "'TABLE'", "'TEMP'",
"'TEMPORARY'", "'THEN'", "'TO'", "'TRANSACTION'", "'TRIGGER'", "'UNION'",
"'UNIQUE'", "'UPDATE'", "'USING'", "'VACUUM'", "'VALUES'", "'VIEW'",
"'VIRTUAL'", "'WHEN'", "'WHERE'", "'WITH'", "'WITHOUT'", "'FIRST_VALUE'",
"'OVER'", "'PARTITION'", "'RANGE'", "'PRECEDING'", "'UNBOUNDED'", "'CURRENT'",
"'FOLLOWING'", "'CUME_DIST'", "'DENSE_RANK'", "'LAG'", "'LAST_VALUE'",
"'LEAD'", "'NTH_VALUE'", "'NTILE'", "'PERCENT_RANK'", "'RANK'", "'ROW_NUMBER'",
"'GENERATED'", "'ALWAYS'", "'STORED'", "'TRUE'", "'FALSE'", "'WINDOW'",
"'NULLS'", "'FIRST'", "'LAST'", "'FILTER'", "'GROUPS'", "'EXCLUDE'",
"'TIES'", "'OTHERS'", "'DO'", "'NOTHING'",
}
staticData.SymbolicNames = []string{
"", "SCOL", "DOT", "OPEN_PAR", "CLOSE_PAR", "COMMA", "ASSIGN", "STAR",
"PLUS", "MINUS", "TILDE", "PIPE2", "DIV", "MOD", "LT2", "GT2", "AMP",
"PIPE", "LT", "LT_EQ", "GT", "GT_EQ", "EQ", "NOT_EQ1", "NOT_EQ2", "ABORT_",
"ACTION_", "ADD_", "AFTER_", "ALL_", "ALTER_", "ANALYZE_", "AND_", "AS_",
"ASC_", "ATTACH_", "AUTOINCREMENT_", "BEFORE_", "BEGIN_", "BETWEEN_",
"BY_", "CASCADE_", "CASE_", "CAST_", "CHECK_", "COLLATE_", "COLUMN_",
"COMMIT_", "CONFLICT_", "CONSTRAINT_", "CREATE_", "CROSS_", "CURRENT_DATE_",
"CURRENT_TIME_", "CURRENT_TIMESTAMP_", "DATABASE_", "DEFAULT_", "DEFERRABLE_",
"DEFERRED_", "DELETE_", "DESC_", "DETACH_", "DISTINCT_", "DROP_", "EACH_",
"ELSE_", "END_", "ESCAPE_", "EXCEPT_", "EXCLUSIVE_", "EXISTS_", "EXPLAIN_",
"FAIL_", "FOR_", "FOREIGN_", "FROM_", "FULL_", "GLOB_", "GROUP_", "HAVING_",
"IF_", "IGNORE_", "IMMEDIATE_", "IN_", "INDEX_", "INDEXED_", "INITIALLY_",
"INNER_", "INSERT_", "INSTEAD_", "INTERSECT_", "INTO_", "IS_", "ISNULL_",
"JOIN_", "KEY_", "LEFT_", "LIKE_", "LIMIT_", "MATCH_", "NATURAL_", "NO_",
"NOT_", "NOTNULL_", "NULL_", "OF_", "OFFSET_", "ON_", "OR_", "ORDER_",
"OUTER_", "PLAN_", "PRAGMA_", "PRIMARY_", "QUERY_", "RAISE_", "RECURSIVE_",
"REFERENCES_", "REGEXP_", "REINDEX_", "RELEASE_", "RENAME_", "REPLACE_",
"RESTRICT_", "RETURNING_", "RIGHT_", "ROLLBACK_", "ROW_", "ROWS_", "SAVEPOINT_",
"SELECT_", "SET_", "TABLE_", "TEMP_", "TEMPORARY_", "THEN_", "TO_",
"TRANSACTION_", "TRIGGER_", "UNION_", "UNIQUE_", "UPDATE_", "USING_",
"VACUUM_", "VALUES_", "VIEW_", "VIRTUAL_", "WHEN_", "WHERE_", "WITH_",
"WITHOUT_", "FIRST_VALUE_", "OVER_", "PARTITION_", "RANGE_", "PRECEDING_",
"UNBOUNDED_", "CURRENT_", "FOLLOWING_", "CUME_DIST_", "DENSE_RANK_",
"LAG_", "LAST_VALUE_", "LEAD_", "NTH_VALUE_", "NTILE_", "PERCENT_RANK_",
"RANK_", "ROW_NUMBER_", "GENERATED_", "ALWAYS_", "STORED_", "TRUE_",
"FALSE_", "WINDOW_", "NULLS_", "FIRST_", "LAST_", "FILTER_", "GROUPS_",
"EXCLUDE_", "TIES_", "OTHERS_", "DO_", "NOTHING_", "IDENTIFIER", "NUMERIC_LITERAL",
"BIND_PARAMETER", "STRING_LITERAL", "BLOB_LITERAL", "SINGLE_LINE_COMMENT",
"MULTILINE_COMMENT", "SPACES", "UNEXPECTED_CHAR",
}
staticData.RuleNames = []string{
"SCOL", "DOT", "OPEN_PAR", "CLOSE_PAR", "COMMA", "ASSIGN", "STAR", "PLUS",
"MINUS", "TILDE", "PIPE2", "DIV", "MOD", "LT2", "GT2", "AMP", "PIPE",
"LT", "LT_EQ", "GT", "GT_EQ", "EQ", "NOT_EQ1", "NOT_EQ2", "ABORT_",
"ACTION_", "ADD_", "AFTER_", "ALL_", "ALTER_", "ANALYZE_", "AND_", "AS_",
"ASC_", "ATTACH_", "AUTOINCREMENT_", "BEFORE_", "BEGIN_", "BETWEEN_",
"BY_", "CASCADE_", "CASE_", "CAST_", "CHECK_", "COLLATE_", "COLUMN_",
"COMMIT_", "CONFLICT_", "CONSTRAINT_", "CREATE_", "CROSS_", "CURRENT_DATE_",
"CURRENT_TIME_", "CURRENT_TIMESTAMP_", "DATABASE_", "DEFAULT_", "DEFERRABLE_",
"DEFERRED_", "DELETE_", "DESC_", "DETACH_", "DISTINCT_", "DROP_", "EACH_",
"ELSE_", "END_", "ESCAPE_", "EXCEPT_", "EXCLUSIVE_", "EXISTS_", "EXPLAIN_",
"FAIL_", "FOR_", "FOREIGN_", "FROM_", "FULL_", "GLOB_", "GROUP_", "HAVING_",
"IF_", "IGNORE_", "IMMEDIATE_", "IN_", "INDEX_", "INDEXED_", "INITIALLY_",
"INNER_", "INSERT_", "INSTEAD_", "INTERSECT_", "INTO_", "IS_", "ISNULL_",
"JOIN_", "KEY_", "LEFT_", "LIKE_", "LIMIT_", "MATCH_", "NATURAL_", "NO_",
"NOT_", "NOTNULL_", "NULL_", "OF_", "OFFSET_", "ON_", "OR_", "ORDER_",
"OUTER_", "PLAN_", "PRAGMA_", "PRIMARY_", "QUERY_", "RAISE_", "RECURSIVE_",
"REFERENCES_", "REGEXP_", "REINDEX_", "RELEASE_", "RENAME_", "REPLACE_",
"RESTRICT_", "RETURNING_", "RIGHT_", "ROLLBACK_", "ROW_", "ROWS_", "SAVEPOINT_",
"SELECT_", "SET_", "TABLE_", "TEMP_", "TEMPORARY_", "THEN_", "TO_",
"TRANSACTION_", "TRIGGER_", "UNION_", "UNIQUE_", "UPDATE_", "USING_",
"VACUUM_", "VALUES_", "VIEW_", "VIRTUAL_", "WHEN_", "WHERE_", "WITH_",
"WITHOUT_", "FIRST_VALUE_", "OVER_", "PARTITION_", "RANGE_", "PRECEDING_",
"UNBOUNDED_", "CURRENT_", "FOLLOWING_", "CUME_DIST_", "DENSE_RANK_",
"LAG_", "LAST_VALUE_", "LEAD_", "NTH_VALUE_", "NTILE_", "PERCENT_RANK_",
"RANK_", "ROW_NUMBER_", "GENERATED_", "ALWAYS_", "STORED_", "TRUE_",
"FALSE_", "WINDOW_", "NULLS_", "FIRST_", "LAST_", "FILTER_", "GROUPS_",
"EXCLUDE_", "TIES_", "OTHERS_", "DO_", "NOTHING_", "IDENTIFIER", "NUMERIC_LITERAL",
"BIND_PARAMETER", "STRING_LITERAL", "BLOB_LITERAL", "SINGLE_LINE_COMMENT",
"MULTILINE_COMMENT", "SPACES", "UNEXPECTED_CHAR", "HEX_DIGIT", "DIGIT",
}
staticData.PredictionContextCache = antlr.NewPredictionContextCache()
staticData.serializedATN = []int32{
4, 0, 193, 1704, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3,
2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9,
2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2,
15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20,
7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7,
25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30,
2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2,
36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41,
7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7,
46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51,
2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2,
57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62,
7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7,
67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72,
2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2,
78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83,
7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7,
88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93,
2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2,
99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103,
2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108,
7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112,
2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117,
7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121,
2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126,
7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130,
2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135,
7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139,
2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144,
7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148,
2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153,
7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157,
2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162,
7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166,
2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171,
7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175,
2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180,
7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184,
2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 2, 189,
7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193,
2, 194, 7, 194, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1,
4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1,
10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14,
1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1,
19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22,
1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1,
25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27,
1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1,
29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30,
1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 33, 1,
33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35,
1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1,
35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37,
1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1,
38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40,
1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1,
42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44,
1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1,
45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47,
1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1,
48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1,
50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51,
1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1,
52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53,
1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1,
53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54,
1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1,
56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57,
1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1,
58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60,
1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1,
61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63,
1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1,
65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67,
1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1,
68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69,
1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1,
71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73,
1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1,
74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76,
1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1,
78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80,
1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1,
81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83,
1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1,
85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86,
1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1,
88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89,
1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1,
90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92,
1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1,
95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 97,
1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1,
98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1,
100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1,
102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 103, 1,
103, 1, 104, 1, 104, 1, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1,
105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 108, 1,
108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 1, 109, 1, 109, 1,
109, 1, 109, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1,
111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1,
112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1,
113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1,
115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 116, 1,
116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1,
116, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1,
118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1,
119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1,
120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1,
121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1,
122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1,
123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1,
124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1,
125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1,
127, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1,
128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1,
130, 1, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 131, 1, 131, 1, 131, 1,
131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1,
133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1,
134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1,
136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1,
137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 138, 1,
138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 139, 1,
139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1,
140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1,
142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 1, 143, 1, 143, 1, 143, 1,
143, 1, 143, 1, 143, 1, 144, 1, 144, 1, 144, 1, 144, 1, 144, 1, 145, 1,
145, 1, 145, 1, 145, 1, 145, 1, 145, 1, 145, 1, 145, 1, 146, 1, 146, 1,
146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1,
148, 1, 148, 1, 148, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 1, 149, 1,
149, 1, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1,
150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1,
151, 1, 151, 1, 151, 1, 152, 1, 152, 1, 152, 1, 152, 1, 152, 1, 152, 1,
152, 1, 152, 1, 152, 1, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 153, 1,
153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 154, 1, 154, 1, 154, 1, 154, 1,
154, 1, 154, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1,
155, 1, 155, 1, 155, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1,
156, 1, 156, 1, 157, 1, 157, 1, 157, 1, 157, 1, 157, 1, 157, 1, 157, 1,
157, 1, 157, 1, 157, 1, 158, 1, 158, 1, 158, 1, 158, 1, 158, 1, 158, 1,
158, 1, 158, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1,
159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1,
160, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1,
161, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 163, 1,
163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1,
164, 1, 164, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1,
165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1,
165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1,
167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1,
168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1,
169, 1, 169, 1, 169, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1,
170, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1,
171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, 1, 173, 1,
173, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, 1,
174, 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1,
176, 1, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1,
177, 1, 177, 1, 178, 1, 178, 1, 178, 1, 178, 1, 178, 1, 178, 1, 178, 1,
179, 1, 179, 1, 179, 1, 179, 1, 179, 1, 179, 1, 179, 1, 179, 1, 180, 1,
180, 1, 180, 1, 180, 1, 180, 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 1,
181, 1, 181, 1, 182, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, 183, 1,
183, 1, 183, 1, 183, 1, 183, 1, 184, 1, 184, 1, 184, 1, 184, 5, 184, 1562,
8, 184, 10, 184, 12, 184, 1565, 9, 184, 1, 184, 1, 184, 1, 184, 1, 184,
1, 184, 5, 184, 1572, 8, 184, 10, 184, 12, 184, 1575, 9, 184, 1, 184, 1,
184, 1, 184, 5, 184, 1580, 8, 184, 10, 184, 12, 184, 1583, 9, 184, 1, 184,
1, 184, 1, 184, 5, 184, 1588, 8, 184, 10, 184, 12, 184, 1591, 9, 184, 3,
184, 1593, 8, 184, 1, 185, 4, 185, 1596, 8, 185, 11, 185, 12, 185, 1597,
1, 185, 1, 185, 5, 185, 1602, 8, 185, 10, 185, 12, 185, 1605, 9, 185, 3,
185, 1607, 8, 185, 1, 185, 1, 185, 4, 185, 1611, 8, 185, 11, 185, 12, 185,
1612, 3, 185, 1615, 8, 185, 1, 185, 1, 185, 3, 185, 1619, 8, 185, 1, 185,
4, 185, 1622, 8, 185, 11, 185, 12, 185, 1623, 3, 185, 1626, 8, 185, 1,
185, 1, 185, 1, 185, 1, 185, 4, 185, 1632, 8, 185, 11, 185, 12, 185, 1633,
3, 185, 1636, 8, 185, 1, 186, 1, 186, 5, 186, 1640, 8, 186, 10, 186, 12,
186, 1643, 9, 186, 1, 186, 1, 186, 3, 186, 1647, 8, 186, 1, 187, 1, 187,
1, 187, 1, 187, 5, 187, 1653, 8, 187, 10, 187, 12, 187, 1656, 9, 187, 1,
187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 189, 1, 189, 1, 189, 1, 189, 5,
189, 1667, 8, 189, 10, 189, 12, 189, 1670, 9, 189, 1, 189, 3, 189, 1673,
8, 189, 1, 189, 1, 189, 3, 189, 1677, 8, 189, 1, 189, 1, 189, 1, 190, 1,
190, 1, 190, 1, 190, 5, 190, 1685, 8, 190, 10, 190, 12, 190, 1688, 9, 190,
1, 190, 1, 190, 1, 190, 1, 190, 1, 190, 1, 191, 1, 191, 1, 191, 1, 191,
1, 192, 1, 192, 1, 193, 1, 193, 1, 194, 1, 194, 1, 1686, 0, 195, 1, 1,
3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23,
12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41,
21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59,
30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77,
39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 95,
48, 97, 49, 99, 50, 101, 51, 103, 52, 105, 53, 107, 54, 109, 55, 111, 56,
113, 57, 115, 58, 117, 59, 119, 60, 121, 61, 123, 62, 125, 63, 127, 64,
129, 65, 131, 66, 133, 67, 135, 68, 137, 69, 139, 70, 141, 71, 143, 72,
145, 73, 147, 74, 149, 75, 151, 76, 153, 77, 155, 78, 157, 79, 159, 80,
161, 81, 163, 82, 165, 83, 167, 84, 169, 85, 171, 86, 173, 87, 175, 88,
177, 89, 179, 90, 181, 91, 183, 92, 185, 93, 187, 94, 189, 95, 191, 96,
193, 97, 195, 98, 197, 99, 199, 100, 201, 101, 203, 102, 205, 103, 207,
104, 209, 105, 211, 106, 213, 107, 215, 108, 217, 109, 219, 110, 221, 111,
223, 112, 225, 113, 227, 114, 229, 115, 231, 116, 233, 117, 235, 118, 237,
119, 239, 120, 241, 121, 243, 122, 245, 123, 247, 124, 249, 125, 251, 126,
253, 127, 255, 128, 257, 129, 259, 130, 261, 131, 263, 132, 265, 133, 267,
134, 269, 135, 271, 136, 273, 137, 275, 138, 277, 139, 279, 140, 281, 141,
283, 142, 285, 143, 287, 144, 289, 145, 291, 146, 293, 147, 295, 148, 297,
149, 299, 150, 301, 151, 303, 152, 305, 153, 307, 154, 309, 155, 311, 156,
313, 157, 315, 158, 317, 159, 319, 160, 321, 161, 323, 162, 325, 163, 327,
164, 329, 165, 331, 166, 333, 167, 335, 168, 337, 169, 339, 170, 341, 171,
343, 172, 345, 173, 347, 174, 349, 175, 351, 176, 353, 177, 355, 178, 357,
179, 359, 180, 361, 181, 363, 182, 365, 183, 367, 184, 369, 185, 371, 186,
373, 187, 375, 188, 377, 189, 379, 190, 381, 191, 383, 192, 385, 193, 387,
0, 389, 0, 1, 0, 38, 2, 0, 65, 65, 97, 97, 2, 0, 66, 66, 98, 98, 2, 0,
79, 79, 111, 111, 2, 0, 82, 82, 114, 114, 2, 0, 84, 84, 116, 116, 2, 0,
67, 67, 99, 99, 2, 0, 73, 73, 105, 105, 2, 0, 78, 78, 110, 110, 2, 0, 68,
68, 100, 100, 2, 0, 70, 70, 102, 102, 2, 0, 69, 69, 101, 101, 2, 0, 76,
76, 108, 108, 2, 0, 89, 89, 121, 121, 2, 0, 90, 90, 122, 122, 2, 0, 83,
83, 115, 115, 2, 0, 72, 72, 104, 104, 2, 0, 85, 85, 117, 117, 2, 0, 77,
77, 109, 109, 2, 0, 71, 71, 103, 103, 2, 0, 87, 87, 119, 119, 2, 0, 75,
75, 107, 107, 2, 0, 80, 80, 112, 112, 2, 0, 88, 88, 120, 120, 2, 0, 86,
86, 118, 118, 2, 0, 74, 74, 106, 106, 2, 0, 81, 81, 113, 113, 1, 0, 34,
34, 1, 0, 96, 96, 1, 0, 93, 93, 3, 0, 65, 90, 95, 95, 97, 122, 4, 0, 48,
57, 65, 90, 95, 95, 97, 122, 2, 0, 43, 43, 45, 45, 3, 0, 36, 36, 58, 58,
64, 64, 1, 0, 39, 39, 2, 0, 10, 10, 13, 13, 3, 0, 9, 11, 13, 13, 32, 32,
3, 0, 48, 57, 65, 70, 97, 102, 1, 0, 48, 57, 1728, 0, 1, 1, 0, 0, 0, 0,
3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0,
11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0,
0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0,
0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0,
0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1,
0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49,
1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0,
57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0,
0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0,
0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0,
0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1,
0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95,
1, 0, 0, 0, 0, 97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 101, 1, 0, 0, 0, 0,
103, 1, 0, 0, 0, 0, 105, 1, 0, 0, 0, 0, 107, 1, 0, 0, 0, 0, 109, 1, 0,
0, 0, 0, 111, 1, 0, 0, 0, 0, 113, 1, 0, 0, 0, 0, 115, 1, 0, 0, 0, 0, 117,
1, 0, 0, 0, 0, 119, 1, 0, 0, 0, 0, 121, 1, 0, 0, 0, 0, 123, 1, 0, 0, 0,
0, 125, 1, 0, 0, 0, 0, 127, 1, 0, 0, 0, 0, 129, 1, 0, 0, 0, 0, 131, 1,
0, 0, 0, 0, 133, 1, 0, 0, 0, 0, 135, 1, 0, 0, 0, 0, 137, 1, 0, 0, 0, 0,
139, 1, 0, 0, 0, 0, 141, 1, 0, 0, 0, 0, 143, 1, 0, 0, 0, 0, 145, 1, 0,
0, 0, 0, 147, 1, 0, 0, 0, 0, 149, 1, 0, 0, 0, 0, 151, 1, 0, 0, 0, 0, 153,
1, 0, 0, 0, 0, 155, 1, 0, 0, 0, 0, 157, 1, 0, 0, 0, 0, 159, 1, 0, 0, 0,
0, 161, 1, 0, 0, 0, 0, 163, 1, 0, 0, 0, 0, 165, 1, 0, 0, 0, 0, 167, 1,
0, 0, 0, 0, 169, 1, 0, 0, 0, 0, 171, 1, 0, 0, 0, 0, 173, 1, 0, 0, 0, 0,
175, 1, 0, 0, 0, 0, 177, 1, 0, 0, 0, 0, 179, 1, 0, 0, 0, 0, 181, 1, 0,
0, 0, 0, 183, 1, 0, 0, 0, 0, 185, 1, 0, 0, 0, 0, 187, 1, 0, 0, 0, 0, 189,
1, 0, 0, 0, 0, 191, 1, 0, 0, 0, 0, 193, 1, 0, 0, 0, 0, 195, 1, 0, 0, 0,
0, 197, 1, 0, 0, 0, 0, 199, 1, 0, 0, 0, 0, 201, 1, 0, 0, 0, 0, 203, 1,
0, 0, 0, 0, 205, 1, 0, 0, 0, 0, 207, 1, 0, 0, 0, 0, 209, 1, 0, 0, 0, 0,
211, 1, 0, 0, 0, 0, 213, 1, 0, 0, 0, 0, 215, 1, 0, 0, 0, 0, 217, 1, 0,
0, 0, 0, 219, 1, 0, 0, 0, 0, 221, 1, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 225,
1, 0, 0, 0, 0, 227, 1, 0, 0, 0, 0, 229, 1, 0, 0, 0, 0, 231, 1, 0, 0, 0,
0, 233, 1, 0, 0, 0, 0, 235, 1, 0, 0, 0, 0, 237, 1, 0, 0, 0, 0, 239, 1,
0, 0, 0, 0, 241, 1, 0, 0, 0, 0, 243, 1, 0, 0, 0, 0, 245, 1, 0, 0, 0, 0,
247, 1, 0, 0, 0, 0, 249, 1, 0, 0, 0, 0, 251, 1, 0, 0, 0, 0, 253, 1, 0,
0, 0, 0, 255, 1, 0, 0, 0, 0, 257, 1, 0, 0, 0, 0, 259, 1, 0, 0, 0, 0, 261,
1, 0, 0, 0, 0, 263, 1, 0, 0, 0, 0, 265, 1, 0, 0, 0, 0, 267, 1, 0, 0, 0,
0, 269, 1, 0, 0, 0, 0, 271, 1, 0, 0, 0, 0, 273, 1, 0, 0, 0, 0, 275, 1,
0, 0, 0, 0, 277, 1, 0, 0, 0, 0, 279, 1, 0, 0, 0, 0, 281, 1, 0, 0, 0, 0,
283, 1, 0, 0, 0, 0, 285, 1, 0, 0, 0, 0, 287, 1, 0, 0, 0, 0, 289, 1, 0,
0, 0, 0, 291, 1, 0, 0, 0, 0, 293, 1, 0, 0, 0, 0, 295, 1, 0, 0, 0, 0, 297,
1, 0, 0, 0, 0, 299, 1, 0, 0, 0, 0, 301, 1, 0, 0, 0, 0, 303, 1, 0, 0, 0,
0, 305, 1, 0, 0, 0, 0, 307, 1, 0, 0, 0, 0, 309, 1, 0, 0, 0, 0, 311, 1,
0, 0, 0, 0, 313, 1, 0, 0, 0, 0, 315, 1, 0, 0, 0, 0, 317, 1, 0, 0, 0, 0,
319, 1, 0, 0, 0, 0, 321, 1, 0, 0, 0, 0, 323, 1, 0, 0, 0, 0, 325, 1, 0,
0, 0, 0, 327, 1, 0, 0, 0, 0, 329, 1, 0, 0, 0, 0, 331, 1, 0, 0, 0, 0, 333,
1, 0, 0, 0, 0, 335, 1, 0, 0, 0, 0, 337, 1, 0, 0, 0, 0, 339, 1, 0, 0, 0,
0, 341, 1, 0, 0, 0, 0, 343, 1, 0, 0, 0, 0, 345, 1, 0, 0, 0, 0, 347, 1,
0, 0, 0, 0, 349, 1, 0, 0, 0, 0, 351, 1, 0, 0, 0, 0, 353, 1, 0, 0, 0, 0,
355, 1, 0, 0, 0, 0, 357, 1, 0, 0, 0, 0, 359, 1, 0, 0, 0, 0, 361, 1, 0,
0, 0, 0, 363, 1, 0, 0, 0, 0, 365, 1, 0, 0, 0, 0, 367, 1, 0, 0, 0, 0, 369,
1, 0, 0, 0, 0, 371, 1, 0, 0, 0, 0, 373, 1, 0, 0, 0, 0, 375, 1, 0, 0, 0,
0, 377, 1, 0, 0, 0, 0, 379, 1, 0, 0, 0, 0, 381, 1, 0, 0, 0, 0, 383, 1,
0, 0, 0, 0, 385, 1, 0, 0, 0, 1, 391, 1, 0, 0, 0, 3, 393, 1, 0, 0, 0, 5,
395, 1, 0, 0, 0, 7, 397, 1, 0, 0, 0, 9, 399, 1, 0, 0, 0, 11, 401, 1, 0,
0, 0, 13, 403, 1, 0, 0, 0, 15, 405, 1, 0, 0, 0, 17, 407, 1, 0, 0, 0, 19,
409, 1, 0, 0, 0, 21, 411, 1, 0, 0, 0, 23, 414, 1, 0, 0, 0, 25, 416, 1,
0, 0, 0, 27, 418, 1, 0, 0, 0, 29, 421, 1, 0, 0, 0, 31, 424, 1, 0, 0, 0,
33, 426, 1, 0, 0, 0, 35, 428, 1, 0, 0, 0, 37, 430, 1, 0, 0, 0, 39, 433,
1, 0, 0, 0, 41, 435, 1, 0, 0, 0, 43, 438, 1, 0, 0, 0, 45, 441, 1, 0, 0,
0, 47, 444, 1, 0, 0, 0, 49, 447, 1, 0, 0, 0, 51, 453, 1, 0, 0, 0, 53, 460,
1, 0, 0, 0, 55, 464, 1, 0, 0, 0, 57, 470, 1, 0, 0, 0, 59, 474, 1, 0, 0,
0, 61, 480, 1, 0, 0, 0, 63, 488, 1, 0, 0, 0, 65, 492, 1, 0, 0, 0, 67, 495,
1, 0, 0, 0, 69, 499, 1, 0, 0, 0, 71, 506, 1, 0, 0, 0, 73, 520, 1, 0, 0,
0, 75, 527, 1, 0, 0, 0, 77, 533, 1, 0, 0, 0, 79, 541, 1, 0, 0, 0, 81, 544,
1, 0, 0, 0, 83, 552, 1, 0, 0, 0, 85, 557, 1, 0, 0, 0, 87, 562, 1, 0, 0,
0, 89, 568, 1, 0, 0, 0, 91, 576, 1, 0, 0, 0, 93, 583, 1, 0, 0, 0, 95, 590,
1, 0, 0, 0, 97, 599, 1, 0, 0, 0, 99, 610, 1, 0, 0, 0, 101, 617, 1, 0, 0,
0, 103, 623, 1, 0, 0, 0, 105, 636, 1, 0, 0, 0, 107, 649, 1, 0, 0, 0, 109,
667, 1, 0, 0, 0, 111, 676, 1, 0, 0, 0, 113, 684, 1, 0, 0, 0, 115, 695,
1, 0, 0, 0, 117, 704, 1, 0, 0, 0, 119, 711, 1, 0, 0, 0, 121, 716, 1, 0,
0, 0, 123, 723, 1, 0, 0, 0, 125, 732, 1, 0, 0, 0, 127, 737, 1, 0, 0, 0,
129, 742, 1, 0, 0, 0, 131, 747, 1, 0, 0, 0, 133, 751, 1, 0, 0, 0, 135,
758, 1, 0, 0, 0, 137, 765, 1, 0, 0, 0, 139, 775, 1, 0, 0, 0, 141, 782,
1, 0, 0, 0, 143, 790, 1, 0, 0, 0, 145, 795, 1, 0, 0, 0, 147, 799, 1, 0,
0, 0, 149, 807, 1, 0, 0, 0, 151, 812, 1, 0, 0, 0, 153, 817, 1, 0, 0, 0,
155, 822, 1, 0, 0, 0, 157, 828, 1, 0, 0, 0, 159, 835, 1, 0, 0, 0, 161,
838, 1, 0, 0, 0, 163, 845, 1, 0, 0, 0, 165, 855, 1, 0, 0, 0, 167, 858,
1, 0, 0, 0, 169, 864, 1, 0, 0, 0, 171, 872, 1, 0, 0, 0, 173, 882, 1, 0,
0, 0, 175, 888, 1, 0, 0, 0, 177, 895, 1, 0, 0, 0, 179, 903, 1, 0, 0, 0,
181, 913, 1, 0, 0, 0, 183, 918, 1, 0, 0, 0, 185, 921, 1, 0, 0, 0, 187,
928, 1, 0, 0, 0, 189, 933, 1, 0, 0, 0, 191, 937, 1, 0, 0, 0, 193, 942,
1, 0, 0, 0, 195, 947, 1, 0, 0, 0, 197, 953, 1, 0, 0, 0, 199, 959, 1, 0,
0, 0, 201, 967, 1, 0, 0, 0, 203, 970, 1, 0, 0, 0, 205, 974, 1, 0, 0, 0,
207, 982, 1, 0, 0, 0, 209, 987, 1, 0, 0, 0, 211, 990, 1, 0, 0, 0, 213,
997, 1, 0, 0, 0, 215, 1000, 1, 0, 0, 0, 217, 1003, 1, 0, 0, 0, 219, 1009,
1, 0, 0, 0, 221, 1015, 1, 0, 0, 0, 223, 1020, 1, 0, 0, 0, 225, 1027, 1,
0, 0, 0, 227, 1035, 1, 0, 0, 0, 229, 1041, 1, 0, 0, 0, 231, 1047, 1, 0,
0, 0, 233, 1057, 1, 0, 0, 0, 235, 1068, 1, 0, 0, 0, 237, 1075, 1, 0, 0,
0, 239, 1083, 1, 0, 0, 0, 241, 1091, 1, 0, 0, 0, 243, 1098, 1, 0, 0, 0,
245, 1106, 1, 0, 0, 0, 247, 1115, 1, 0, 0, 0, 249, 1125, 1, 0, 0, 0, 251,
1131, 1, 0, 0, 0, 253, 1140, 1, 0, 0, 0, 255, 1144, 1, 0, 0, 0, 257, 1149,
1, 0, 0, 0, 259, 1159, 1, 0, 0, 0, 261, 1166, 1, 0, 0, 0, 263, 1170, 1,
0, 0, 0, 265, 1176, 1, 0, 0, 0, 267, 1181, 1, 0, 0, 0, 269, 1191, 1, 0,
0, 0, 271, 1196, 1, 0, 0, 0, 273, 1199, 1, 0, 0, 0, 275, 1211, 1, 0, 0,
0, 277, 1219, 1, 0, 0, 0, 279, 1225, 1, 0, 0, 0, 281, 1232, 1, 0, 0, 0,
283, 1239, 1, 0, 0, 0, 285, 1245, 1, 0, 0, 0, 287, 1252, 1, 0, 0, 0, 289,
1259, 1, 0, 0, 0, 291, 1264, 1, 0, 0, 0, 293, 1272, 1, 0, 0, 0, 295, 1277,
1, 0, 0, 0, 297, 1283, 1, 0, 0, 0, 299, 1288, 1, 0, 0, 0, 301, 1296, 1,
0, 0, 0, 303, 1308, 1, 0, 0, 0, 305, 1313, 1, 0, 0, 0, 307, 1323, 1, 0,
0, 0, 309, 1329, 1, 0, 0, 0, 311, 1339, 1, 0, 0, 0, 313, 1349, 1, 0, 0,
0, 315, 1357, 1, 0, 0, 0, 317, 1367, 1, 0, 0, 0, 319, 1377, 1, 0, 0, 0,
321, 1388, 1, 0, 0, 0, 323, 1392, 1, 0, 0, 0, 325, 1403, 1, 0, 0, 0, 327,
1408, 1, 0, 0, 0, 329, 1418, 1, 0, 0, 0, 331, 1424, 1, 0, 0, 0, 333, 1437,
1, 0, 0, 0, 335, 1442, 1, 0, 0, 0, 337, 1453, 1, 0, 0, 0, 339, 1463, 1,
0, 0, 0, 341, 1470, 1, 0, 0, 0, 343, 1477, 1, 0, 0, 0, 345, 1482, 1, 0,
0, 0, 347, 1488, 1, 0, 0, 0, 349, 1495, 1, 0, 0, 0, 351, 1501, 1, 0, 0,
0, 353, 1507, 1, 0, 0, 0, 355, 1512, 1, 0, 0, 0, 357, 1519, 1, 0, 0, 0,
359, 1526, 1, 0, 0, 0, 361, 1534, 1, 0, 0, 0, 363, 1539, 1, 0, 0, 0, 365,
1546, 1, 0, 0, 0, 367, 1549, 1, 0, 0, 0, 369, 1592, 1, 0, 0, 0, 371, 1635,
1, 0, 0, 0, 373, 1646, 1, 0, 0, 0, 375, 1648, 1, 0, 0, 0, 377, 1659, 1,
0, 0, 0, 379, 1662, 1, 0, 0, 0, 381, 1680, 1, 0, 0, 0, 383, 1694, 1, 0,
0, 0, 385, 1698, 1, 0, 0, 0, 387, 1700, 1, 0, 0, 0, 389, 1702, 1, 0, 0,
0, 391, 392, 5, 59, 0, 0, 392, 2, 1, 0, 0, 0, 393, 394, 5, 46, 0, 0, 394,
4, 1, 0, 0, 0, 395, 396, 5, 40, 0, 0, 396, 6, 1, 0, 0, 0, 397, 398, 5,
41, 0, 0, 398, 8, 1, 0, 0, 0, 399, 400, 5, 44, 0, 0, 400, 10, 1, 0, 0,
0, 401, 402, 5, 61, 0, 0, 402, 12, 1, 0, 0, 0, 403, 404, 5, 42, 0, 0, 404,
14, 1, 0, 0, 0, 405, 406, 5, 43, 0, 0, 406, 16, 1, 0, 0, 0, 407, 408, 5,
45, 0, 0, 408, 18, 1, 0, 0, 0, 409, 410, 5, 126, 0, 0, 410, 20, 1, 0, 0,
0, 411, 412, 5, 124, 0, 0, 412, 413, 5, 124, 0, 0, 413, 22, 1, 0, 0, 0,
414, 415, 5, 47, 0, 0, 415, 24, 1, 0, 0, 0, 416, 417, 5, 37, 0, 0, 417,
26, 1, 0, 0, 0, 418, 419, 5, 60, 0, 0, 419, 420, 5, 60, 0, 0, 420, 28,
1, 0, 0, 0, 421, 422, 5, 62, 0, 0, 422, 423, 5, 62, 0, 0, 423, 30, 1, 0,
0, 0, 424, 425, 5, 38, 0, 0, 425, 32, 1, 0, 0, 0, 426, 427, 5, 124, 0,
0, 427, 34, 1, 0, 0, 0, 428, 429, 5, 60, 0, 0, 429, 36, 1, 0, 0, 0, 430,
431, 5, 60, 0, 0, 431, 432, 5, 61, 0, 0, 432, 38, 1, 0, 0, 0, 433, 434,
5, 62, 0, 0, 434, 40, 1, 0, 0, 0, 435, 436, 5, 62, 0, 0, 436, 437, 5, 61,
0, 0, 437, 42, 1, 0, 0, 0, 438, 439, 5, 61, 0, 0, 439, 440, 5, 61, 0, 0,
440, 44, 1, 0, 0, 0, 441, 442, 5, 33, 0, 0, 442, 443, 5, 61, 0, 0, 443,
46, 1, 0, 0, 0, 444, 445, 5, 60, 0, 0, 445, 446, 5, 62, 0, 0, 446, 48,
1, 0, 0, 0, 447, 448, 7, 0, 0, 0, 448, 449, 7, 1, 0, 0, 449, 450, 7, 2,
0, 0, 450, 451, 7, 3, 0, 0, 451, 452, 7, 4, 0, 0, 452, 50, 1, 0, 0, 0,
453, 454, 7, 0, 0, 0, 454, 455, 7, 5, 0, 0, 455, 456, 7, 4, 0, 0, 456,
457, 7, 6, 0, 0, 457, 458, 7, 2, 0, 0, 458, 459, 7, 7, 0, 0, 459, 52, 1,
0, 0, 0, 460, 461, 7, 0, 0, 0, 461, 462, 7, 8, 0, 0, 462, 463, 7, 8, 0,
0, 463, 54, 1, 0, 0, 0, 464, 465, 7, 0, 0, 0, 465, 466, 7, 9, 0, 0, 466,
467, 7, 4, 0, 0, 467, 468, 7, 10, 0, 0, 468, 469, 7, 3, 0, 0, 469, 56,
1, 0, 0, 0, 470, 471, 7, 0, 0, 0, 471, 472, 7, 11, 0, 0, 472, 473, 7, 11,
0, 0, 473, 58, 1, 0, 0, 0, 474, 475, 7, 0, 0, 0, 475, 476, 7, 11, 0, 0,
476, 477, 7, 4, 0, 0, 477, 478, 7, 10, 0, 0, 478, 479, 7, 3, 0, 0, 479,
60, 1, 0, 0, 0, 480, 481, 7, 0, 0, 0, 481, 482, 7, 7, 0, 0, 482, 483, 7,
0, 0, 0, 483, 484, 7, 11, 0, 0, 484, 485, 7, 12, 0, 0, 485, 486, 7, 13,
0, 0, 486, 487, 7, 10, 0, 0, 487, 62, 1, 0, 0, 0, 488, 489, 7, 0, 0, 0,
489, 490, 7, 7, 0, 0, 490, 491, 7, 8, 0, 0, 491, 64, 1, 0, 0, 0, 492, 493,
7, 0, 0, 0, 493, 494, 7, 14, 0, 0, 494, 66, 1, 0, 0, 0, 495, 496, 7, 0,
0, 0, 496, 497, 7, 14, 0, 0, 497, 498, 7, 5, 0, 0, 498, 68, 1, 0, 0, 0,
499, 500, 7, 0, 0, 0, 500, 501, 7, 4, 0, 0, 501, 502, 7, 4, 0, 0, 502,
503, 7, 0, 0, 0, 503, 504, 7, 5, 0, 0, 504, 505, 7, 15, 0, 0, 505, 70,
1, 0, 0, 0, 506, 507, 7, 0, 0, 0, 507, 508, 7, 16, 0, 0, 508, 509, 7, 4,
0, 0, 509, 510, 7, 2, 0, 0, 510, 511, 7, 6, 0, 0, 511, 512, 7, 7, 0, 0,
512, 513, 7, 5, 0, 0, 513, 514, 7, 3, 0, 0, 514, 515, 7, 10, 0, 0, 515,
516, 7, 17, 0, 0, 516, 517, 7, 10, 0, 0, 517, 518, 7, 7, 0, 0, 518, 519,
7, 4, 0, 0, 519, 72, 1, 0, 0, 0, 520, 521, 7, 1, 0, 0, 521, 522, 7, 10,
0, 0, 522, 523, 7, 9, 0, 0, 523, 524, 7, 2, 0, 0, 524, 525, 7, 3, 0, 0,
525, 526, 7, 10, 0, 0, 526, 74, 1, 0, 0, 0, 527, 528, 7, 1, 0, 0, 528,
529, 7, 10, 0, 0, 529, 530, 7, 18, 0, 0, 530, 531, 7, 6, 0, 0, 531, 532,
7, 7, 0, 0, 532, 76, 1, 0, 0, 0, 533, 534, 7, 1, 0, 0, 534, 535, 7, 10,
0, 0, 535, 536, 7, 4, 0, 0, 536, 537, 7, 19, 0, 0, 537, 538, 7, 10, 0,
0, 538, 539, 7, 10, 0, 0, 539, 540, 7, 7, 0, 0, 540, 78, 1, 0, 0, 0, 541,
542, 7, 1, 0, 0, 542, 543, 7, 12, 0, 0, 543, 80, 1, 0, 0, 0, 544, 545,
7, 5, 0, 0, 545, 546, 7, 0, 0, 0, 546, 547, 7, 14, 0, 0, 547, 548, 7, 5,
0, 0, 548, 549, 7, 0, 0, 0, 549, 550, 7, 8, 0, 0, 550, 551, 7, 10, 0, 0,
551, 82, 1, 0, 0, 0, 552, 553, 7, 5, 0, 0, 553, 554, 7, 0, 0, 0, 554, 555,
7, 14, 0, 0, 555, 556, 7, 10, 0, 0, 556, 84, 1, 0, 0, 0, 557, 558, 7, 5,
0, 0, 558, 559, 7, 0, 0, 0, 559, 560, 7, 14, 0, 0, 560, 561, 7, 4, 0, 0,
561, 86, 1, 0, 0, 0, 562, 563, 7, 5, 0, 0, 563, 564, 7, 15, 0, 0, 564,
565, 7, 10, 0, 0, 565, 566, 7, 5, 0, 0, 566, 567, 7, 20, 0, 0, 567, 88,
1, 0, 0, 0, 568, 569, 7, 5, 0, 0, 569, 570, 7, 2, 0, 0, 570, 571, 7, 11,
0, 0, 571, 572, 7, 11, 0, 0, 572, 573, 7, 0, 0, 0, 573, 574, 7, 4, 0, 0,
574, 575, 7, 10, 0, 0, 575, 90, 1, 0, 0, 0, 576, 577, 7, 5, 0, 0, 577,
578, 7, 2, 0, 0, 578, 579, 7, 11, 0, 0, 579, 580, 7, 16, 0, 0, 580, 581,
7, 17, 0, 0, 581, 582, 7, 7, 0, 0, 582, 92, 1, 0, 0, 0, 583, 584, 7, 5,
0, 0, 584, 585, 7, 2, 0, 0, 585, 586, 7, 17, 0, 0, 586, 587, 7, 17, 0,
0, 587, 588, 7, 6, 0, 0, 588, 589, 7, 4, 0, 0, 589, 94, 1, 0, 0, 0, 590,
591, 7, 5, 0, 0, 591, 592, 7, 2, 0, 0, 592, 593, 7, 7, 0, 0, 593, 594,
7, 9, 0, 0, 594, 595, 7, 11, 0, 0, 595, 596, 7, 6, 0, 0, 596, 597, 7, 5,
0, 0, 597, 598, 7, 4, 0, 0, 598, 96, 1, 0, 0, 0, 599, 600, 7, 5, 0, 0,
600, 601, 7, 2, 0, 0, 601, 602, 7, 7, 0, 0, 602, 603, 7, 14, 0, 0, 603,
604, 7, 4, 0, 0, 604, 605, 7, 3, 0, 0, 605, 606, 7, 0, 0, 0, 606, 607,
7, 6, 0, 0, 607, 608, 7, 7, 0, 0, 608, 609, 7, 4, 0, 0, 609, 98, 1, 0,
0, 0, 610, 611, 7, 5, 0, 0, 611, 612, 7, 3, 0, 0, 612, 613, 7, 10, 0, 0,
613, 614, 7, 0, 0, 0, 614, 615, 7, 4, 0, 0, 615, 616, 7, 10, 0, 0, 616,
100, 1, 0, 0, 0, 617, 618, 7, 5, 0, 0, 618, 619, 7, 3, 0, 0, 619, 620,
7, 2, 0, 0, 620, 621, 7, 14, 0, 0, 621, 622, 7, 14, 0, 0, 622, 102, 1,
0, 0, 0, 623, 624, 7, 5, 0, 0, 624, 625, 7, 16, 0, 0, 625, 626, 7, 3, 0,
0, 626, 627, 7, 3, 0, 0, 627, 628, 7, 10, 0, 0, 628, 629, 7, 7, 0, 0, 629,
630, 7, 4, 0, 0, 630, 631, 5, 95, 0, 0, 631, 632, 7, 8, 0, 0, 632, 633,
7, 0, 0, 0, 633, 634, 7, 4, 0, 0, 634, 635, 7, 10, 0, 0, 635, 104, 1, 0,
0, 0, 636, 637, 7, 5, 0, 0, 637, 638, 7, 16, 0, 0, 638, 639, 7, 3, 0, 0,
639, 640, 7, 3, 0, 0, 640, 641, 7, 10, 0, 0, 641, 642, 7, 7, 0, 0, 642,
643, 7, 4, 0, 0, 643, 644, 5, 95, 0, 0, 644, 645, 7, 4, 0, 0, 645, 646,
7, 6, 0, 0, 646, 647, 7, 17, 0, 0, 647, 648, 7, 10, 0, 0, 648, 106, 1,
0, 0, 0, 649, 650, 7, 5, 0, 0, 650, 651, 7, 16, 0, 0, 651, 652, 7, 3, 0,
0, 652, 653, 7, 3, 0, 0, 653, 654, 7, 10, 0, 0, 654, 655, 7, 7, 0, 0, 655,
656, 7, 4, 0, 0, 656, 657, 5, 95, 0, 0, 657, 658, 7, 4, 0, 0, 658, 659,
7, 6, 0, 0, 659, 660, 7, 17, 0, 0, 660, 661, 7, 10, 0, 0, 661, 662, 7,
14, 0, 0, 662, 663, 7, 4, 0, 0, 663, 664, 7, 0, 0, 0, 664, 665, 7, 17,
0, 0, 665, 666, 7, 21, 0, 0, 666, 108, 1, 0, 0, 0, 667, 668, 7, 8, 0, 0,
668, 669, 7, 0, 0, 0, 669, 670, 7, 4, 0, 0, 670, 671, 7, 0, 0, 0, 671,
672, 7, 1, 0, 0, 672, 673, 7, 0, 0, 0, 673, 674, 7, 14, 0, 0, 674, 675,
7, 10, 0, 0, 675, 110, 1, 0, 0, 0, 676, 677, 7, 8, 0, 0, 677, 678, 7, 10,
0, 0, 678, 679, 7, 9, 0, 0, 679, 680, 7, 0, 0, 0, 680, 681, 7, 16, 0, 0,
681, 682, 7, 11, 0, 0, 682, 683, 7, 4, 0, 0, 683, 112, 1, 0, 0, 0, 684,
685, 7, 8, 0, 0, 685, 686, 7, 10, 0, 0, 686, 687, 7, 9, 0, 0, 687, 688,
7, 10, 0, 0, 688, 689, 7, 3, 0, 0, 689, 690, 7, 3, 0, 0, 690, 691, 7, 0,
0, 0, 691, 692, 7, 1, 0, 0, 692, 693, 7, 11, 0, 0, 693, 694, 7, 10, 0,
0, 694, 114, 1, 0, 0, 0, 695, 696, 7, 8, 0, 0, 696, 697, 7, 10, 0, 0, 697,
698, 7, 9, 0, 0, 698, 699, 7, 10, 0, 0, 699, 700, 7, 3, 0, 0, 700, 701,
7, 3, 0, 0, 701, 702, 7, 10, 0, 0, 702, 703, 7, 8, 0, 0, 703, 116, 1, 0,
0, 0, 704, 705, 7, 8, 0, 0, 705, 706, 7, 10, 0, 0, 706, 707, 7, 11, 0,
0, 707, 708, 7, 10, 0, 0, 708, 709, 7, 4, 0, 0, 709, 710, 7, 10, 0, 0,
710, 118, 1, 0, 0, 0, 711, 712, 7, 8, 0, 0, 712, 713, 7, 10, 0, 0, 713,
714, 7, 14, 0, 0, 714, 715, 7, 5, 0, 0, 715, 120, 1, 0, 0, 0, 716, 717,
7, 8, 0, 0, 717, 718, 7, 10, 0, 0, 718, 719, 7, 4, 0, 0, 719, 720, 7, 0,
0, 0, 720, 721, 7, 5, 0, 0, 721, 722, 7, 15, 0, 0, 722, 122, 1, 0, 0, 0,
723, 724, 7, 8, 0, 0, 724, 725, 7, 6, 0, 0, 725, 726, 7, 14, 0, 0, 726,
727, 7, 4, 0, 0, 727, 728, 7, 6, 0, 0, 728, 729, 7, 7, 0, 0, 729, 730,
7, 5, 0, 0, 730, 731, 7, 4, 0, 0, 731, 124, 1, 0, 0, 0, 732, 733, 7, 8,
0, 0, 733, 734, 7, 3, 0, 0, 734, 735, 7, 2, 0, 0, 735, 736, 7, 21, 0, 0,
736, 126, 1, 0, 0, 0, 737, 738, 7, 10, 0, 0, 738, 739, 7, 0, 0, 0, 739,
740, 7, 5, 0, 0, 740, 741, 7, 15, 0, 0, 741, 128, 1, 0, 0, 0, 742, 743,
7, 10, 0, 0, 743, 744, 7, 11, 0, 0, 744, 745, 7, 14, 0, 0, 745, 746, 7,
10, 0, 0, 746, 130, 1, 0, 0, 0, 747, 748, 7, 10, 0, 0, 748, 749, 7, 7,
0, 0, 749, 750, 7, 8, 0, 0, 750, 132, 1, 0, 0, 0, 751, 752, 7, 10, 0, 0,
752, 753, 7, 14, 0, 0, 753, 754, 7, 5, 0, 0, 754, 755, 7, 0, 0, 0, 755,
756, 7, 21, 0, 0, 756, 757, 7, 10, 0, 0, 757, 134, 1, 0, 0, 0, 758, 759,
7, 10, 0, 0, 759, 760, 7, 22, 0, 0, 760, 761, 7, 5, 0, 0, 761, 762, 7,
10, 0, 0, 762, 763, 7, 21, 0, 0, 763, 764, 7, 4, 0, 0, 764, 136, 1, 0,
0, 0, 765, 766, 7, 10, 0, 0, 766, 767, 7, 22, 0, 0, 767, 768, 7, 5, 0,
0, 768, 769, 7, 11, 0, 0, 769, 770, 7, 16, 0, 0, 770, 771, 7, 14, 0, 0,
771, 772, 7, 6, 0, 0, 772, 773, 7, 23, 0, 0, 773, 774, 7, 10, 0, 0, 774,
138, 1, 0, 0, 0, 775, 776, 7, 10, 0, 0, 776, 777, 7, 22, 0, 0, 777, 778,
7, 6, 0, 0, 778, 779, 7, 14, 0, 0, 779, 780, 7, 4, 0, 0, 780, 781, 7, 14,
0, 0, 781, 140, 1, 0, 0, 0, 782, 783, 7, 10, 0, 0, 783, 784, 7, 22, 0,
0, 784, 785, 7, 21, 0, 0, 785, 786, 7, 11, 0, 0, 786, 787, 7, 0, 0, 0,
787, 788, 7, 6, 0, 0, 788, 789, 7, 7, 0, 0, 789, 142, 1, 0, 0, 0, 790,
791, 7, 9, 0, 0, 791, 792, 7, 0, 0, 0, 792, 793, 7, 6, 0, 0, 793, 794,
7, 11, 0, 0, 794, 144, 1, 0, 0, 0, 795, 796, 7, 9, 0, 0, 796, 797, 7, 2,
0, 0, 797, 798, 7, 3, 0, 0, 798, 146, 1, 0, 0, 0, 799, 800, 7, 9, 0, 0,
800, 801, 7, 2, 0, 0, 801, 802, 7, 3, 0, 0, 802, 803, 7, 10, 0, 0, 803,
804, 7, 6, 0, 0, 804, 805, 7, 18, 0, 0, 805, 806, 7, 7, 0, 0, 806, 148,
1, 0, 0, 0, 807, 808, 7, 9, 0, 0, 808, 809, 7, 3, 0, 0, 809, 810, 7, 2,
0, 0, 810, 811, 7, 17, 0, 0, 811, 150, 1, 0, 0, 0, 812, 813, 7, 9, 0, 0,
813, 814, 7, 16, 0, 0, 814, 815, 7, 11, 0, 0, 815, 816, 7, 11, 0, 0, 816,
152, 1, 0, 0, 0, 817, 818, 7, 18, 0, 0, 818, 819, 7, 11, 0, 0, 819, 820,
7, 2, 0, 0, 820, 821, 7, 1, 0, 0, 821, 154, 1, 0, 0, 0, 822, 823, 7, 18,
0, 0, 823, 824, 7, 3, 0, 0, 824, 825, 7, 2, 0, 0, 825, 826, 7, 16, 0, 0,
826, 827, 7, 21, 0, 0, 827, 156, 1, 0, 0, 0, 828, 829, 7, 15, 0, 0, 829,
830, 7, 0, 0, 0, 830, 831, 7, 23, 0, 0, 831, 832, 7, 6, 0, 0, 832, 833,
7, 7, 0, 0, 833, 834, 7, 18, 0, 0, 834, 158, 1, 0, 0, 0, 835, 836, 7, 6,
0, 0, 836, 837, 7, 9, 0, 0, 837, 160, 1, 0, 0, 0, 838, 839, 7, 6, 0, 0,
839, 840, 7, 18, 0, 0, 840, 841, 7, 7, 0, 0, 841, 842, 7, 2, 0, 0, 842,
843, 7, 3, 0, 0, 843, 844, 7, 10, 0, 0, 844, 162, 1, 0, 0, 0, 845, 846,
7, 6, 0, 0, 846, 847, 7, 17, 0, 0, 847, 848, 7, 17, 0, 0, 848, 849, 7,
10, 0, 0, 849, 850, 7, 8, 0, 0, 850, 851, 7, 6, 0, 0, 851, 852, 7, 0, 0,
0, 852, 853, 7, 4, 0, 0, 853, 854, 7, 10, 0, 0, 854, 164, 1, 0, 0, 0, 855,
856, 7, 6, 0, 0, 856, 857, 7, 7, 0, 0, 857, 166, 1, 0, 0, 0, 858, 859,
7, 6, 0, 0, 859, 860, 7, 7, 0, 0, 860, 861, 7, 8, 0, 0, 861, 862, 7, 10,
0, 0, 862, 863, 7, 22, 0, 0, 863, 168, 1, 0, 0, 0, 864, 865, 7, 6, 0, 0,
865, 866, 7, 7, 0, 0, 866, 867, 7, 8, 0, 0, 867, 868, 7, 10, 0, 0, 868,
869, 7, 22, 0, 0, 869, 870, 7, 10, 0, 0, 870, 871, 7, 8, 0, 0, 871, 170,
1, 0, 0, 0, 872, 873, 7, 6, 0, 0, 873, 874, 7, 7, 0, 0, 874, 875, 7, 6,
0, 0, 875, 876, 7, 4, 0, 0, 876, 877, 7, 6, 0, 0, 877, 878, 7, 0, 0, 0,
878, 879, 7, 11, 0, 0, 879, 880, 7, 11, 0, 0, 880, 881, 7, 12, 0, 0, 881,
172, 1, 0, 0, 0, 882, 883, 7, 6, 0, 0, 883, 884, 7, 7, 0, 0, 884, 885,
7, 7, 0, 0, 885, 886, 7, 10, 0, 0, 886, 887, 7, 3, 0, 0, 887, 174, 1, 0,
0, 0, 888, 889, 7, 6, 0, 0, 889, 890, 7, 7, 0, 0, 890, 891, 7, 14, 0, 0,
891, 892, 7, 10, 0, 0, 892, 893, 7, 3, 0, 0, 893, 894, 7, 4, 0, 0, 894,
176, 1, 0, 0, 0, 895, 896, 7, 6, 0, 0, 896, 897, 7, 7, 0, 0, 897, 898,
7, 14, 0, 0, 898, 899, 7, 4, 0, 0, 899, 900, 7, 10, 0, 0, 900, 901, 7,
0, 0, 0, 901, 902, 7, 8, 0, 0, 902, 178, 1, 0, 0, 0, 903, 904, 7, 6, 0,
0, 904, 905, 7, 7, 0, 0, 905, 906, 7, 4, 0, 0, 906, 907, 7, 10, 0, 0, 907,
908, 7, 3, 0, 0, 908, 909, 7, 14, 0, 0, 909, 910, 7, 10, 0, 0, 910, 911,
7, 5, 0, 0, 911, 912, 7, 4, 0, 0, 912, 180, 1, 0, 0, 0, 913, 914, 7, 6,
0, 0, 914, 915, 7, 7, 0, 0, 915, 916, 7, 4, 0, 0, 916, 917, 7, 2, 0, 0,
917, 182, 1, 0, 0, 0, 918, 919, 7, 6, 0, 0, 919, 920, 7, 14, 0, 0, 920,
184, 1, 0, 0, 0, 921, 922, 7, 6, 0, 0, 922, 923, 7, 14, 0, 0, 923, 924,
7, 7, 0, 0, 924, 925, 7, 16, 0, 0, 925, 926, 7, 11, 0, 0, 926, 927, 7,
11, 0, 0, 927, 186, 1, 0, 0, 0, 928, 929, 7, 24, 0, 0, 929, 930, 7, 2,
0, 0, 930, 931, 7, 6, 0, 0, 931, 932, 7, 7, 0, 0, 932, 188, 1, 0, 0, 0,
933, 934, 7, 20, 0, 0, 934, 935, 7, 10, 0, 0, 935, 936, 7, 12, 0, 0, 936,
190, 1, 0, 0, 0, 937, 938, 7, 11, 0, 0, 938, 939, 7, 10, 0, 0, 939, 940,
7, 9, 0, 0, 940, 941, 7, 4, 0, 0, 941, 192, 1, 0, 0, 0, 942, 943, 7, 11,
0, 0, 943, 944, 7, 6, 0, 0, 944, 945, 7, 20, 0, 0, 945, 946, 7, 10, 0,
0, 946, 194, 1, 0, 0, 0, 947, 948, 7, 11, 0, 0, 948, 949, 7, 6, 0, 0, 949,
950, 7, 17, 0, 0, 950, 951, 7, 6, 0, 0, 951, 952, 7, 4, 0, 0, 952, 196,
1, 0, 0, 0, 953, 954, 7, 17, 0, 0, 954, 955, 7, 0, 0, 0, 955, 956, 7, 4,
0, 0, 956, 957, 7, 5, 0, 0, 957, 958, 7, 15, 0, 0, 958, 198, 1, 0, 0, 0,
959, 960, 7, 7, 0, 0, 960, 961, 7, 0, 0, 0, 961, 962, 7, 4, 0, 0, 962,
963, 7, 16, 0, 0, 963, 964, 7, 3, 0, 0, 964, 965, 7, 0, 0, 0, 965, 966,
7, 11, 0, 0, 966, 200, 1, 0, 0, 0, 967, 968, 7, 7, 0, 0, 968, 969, 7, 2,
0, 0, 969, 202, 1, 0, 0, 0, 970, 971, 7, 7, 0, 0, 971, 972, 7, 2, 0, 0,
972, 973, 7, 4, 0, 0, 973, 204, 1, 0, 0, 0, 974, 975, 7, 7, 0, 0, 975,
976, 7, 2, 0, 0, 976, 977, 7, 4, 0, 0, 977, 978, 7, 7, 0, 0, 978, 979,
7, 16, 0, 0, 979, 980, 7, 11, 0, 0, 980, 981, 7, 11, 0, 0, 981, 206, 1,
0, 0, 0, 982, 983, 7, 7, 0, 0, 983, 984, 7, 16, 0, 0, 984, 985, 7, 11,
0, 0, 985, 986, 7, 11, 0, 0, 986, 208, 1, 0, 0, 0, 987, 988, 7, 2, 0, 0,
988, 989, 7, 9, 0, 0, 989, 210, 1, 0, 0, 0, 990, 991, 7, 2, 0, 0, 991,
992, 7, 9, 0, 0, 992, 993, 7, 9, 0, 0, 993, 994, 7, 14, 0, 0, 994, 995,
7, 10, 0, 0, 995, 996, 7, 4, 0, 0, 996, 212, 1, 0, 0, 0, 997, 998, 7, 2,
0, 0, 998, 999, 7, 7, 0, 0, 999, 214, 1, 0, 0, 0, 1000, 1001, 7, 2, 0,
0, 1001, 1002, 7, 3, 0, 0, 1002, 216, 1, 0, 0, 0, 1003, 1004, 7, 2, 0,
0, 1004, 1005, 7, 3, 0, 0, 1005, 1006, 7, 8, 0, 0, 1006, 1007, 7, 10, 0,
0, 1007, 1008, 7, 3, 0, 0, 1008, 218, 1, 0, 0, 0, 1009, 1010, 7, 2, 0,
0, 1010, 1011, 7, 16, 0, 0, 1011, 1012, 7, 4, 0, 0, 1012, 1013, 7, 10,
0, 0, 1013, 1014, 7, 3, 0, 0, 1014, 220, 1, 0, 0, 0, 1015, 1016, 7, 21,
0, 0, 1016, 1017, 7, 11, 0, 0, 1017, 1018, 7, 0, 0, 0, 1018, 1019, 7, 7,
0, 0, 1019, 222, 1, 0, 0, 0, 1020, 1021, 7, 21, 0, 0, 1021, 1022, 7, 3,
0, 0, 1022, 1023, 7, 0, 0, 0, 1023, 1024, 7, 18, 0, 0, 1024, 1025, 7, 17,
0, 0, 1025, 1026, 7, 0, 0, 0, 1026, 224, 1, 0, 0, 0, 1027, 1028, 7, 21,
0, 0, 1028, 1029, 7, 3, 0, 0, 1029, 1030, 7, 6, 0, 0, 1030, 1031, 7, 17,
0, 0, 1031, 1032, 7, 0, 0, 0, 1032, 1033, 7, 3, 0, 0, 1033, 1034, 7, 12,
0, 0, 1034, 226, 1, 0, 0, 0, 1035, 1036, 7, 25, 0, 0, 1036, 1037, 7, 16,
0, 0, 1037, 1038, 7, 10, 0, 0, 1038, 1039, 7, 3, 0, 0, 1039, 1040, 7, 12,
0, 0, 1040, 228, 1, 0, 0, 0, 1041, 1042, 7, 3, 0, 0, 1042, 1043, 7, 0,
0, 0, 1043, 1044, 7, 6, 0, 0, 1044, 1045, 7, 14, 0, 0, 1045, 1046, 7, 10,
0, 0, 1046, 230, 1, 0, 0, 0, 1047, 1048, 7, 3, 0, 0, 1048, 1049, 7, 10,
0, 0, 1049, 1050, 7, 5, 0, 0, 1050, 1051, 7, 16, 0, 0, 1051, 1052, 7, 3,
0, 0, 1052, 1053, 7, 14, 0, 0, 1053, 1054, 7, 6, 0, 0, 1054, 1055, 7, 23,
0, 0, 1055, 1056, 7, 10, 0, 0, 1056, 232, 1, 0, 0, 0, 1057, 1058, 7, 3,
0, 0, 1058, 1059, 7, 10, 0, 0, 1059, 1060, 7, 9, 0, 0, 1060, 1061, 7, 10,
0, 0, 1061, 1062, 7, 3, 0, 0, 1062, 1063, 7, 10, 0, 0, 1063, 1064, 7, 7,
0, 0, 1064, 1065, 7, 5, 0, 0, 1065, 1066, 7, 10, 0, 0, 1066, 1067, 7, 14,
0, 0, 1067, 234, 1, 0, 0, 0, 1068, 1069, 7, 3, 0, 0, 1069, 1070, 7, 10,
0, 0, 1070, 1071, 7, 18, 0, 0, 1071, 1072, 7, 10, 0, 0, 1072, 1073, 7,
22, 0, 0, 1073, 1074, 7, 21, 0, 0, 1074, 236, 1, 0, 0, 0, 1075, 1076, 7,
3, 0, 0, 1076, 1077, 7, 10, 0, 0, 1077, 1078, 7, 6, 0, 0, 1078, 1079, 7,
7, 0, 0, 1079, 1080, 7, 8, 0, 0, 1080, 1081, 7, 10, 0, 0, 1081, 1082, 7,
22, 0, 0, 1082, 238, 1, 0, 0, 0, 1083, 1084, 7, 3, 0, 0, 1084, 1085, 7,
10, 0, 0, 1085, 1086, 7, 11, 0, 0, 1086, 1087, 7, 10, 0, 0, 1087, 1088,
7, 0, 0, 0, 1088, 1089, 7, 14, 0, 0, 1089, 1090, 7, 10, 0, 0, 1090, 240,
1, 0, 0, 0, 1091, 1092, 7, 3, 0, 0, 1092, 1093, 7, 10, 0, 0, 1093, 1094,
7, 7, 0, 0, 1094, 1095, 7, 0, 0, 0, 1095, 1096, 7, 17, 0, 0, 1096, 1097,
7, 10, 0, 0, 1097, 242, 1, 0, 0, 0, 1098, 1099, 7, 3, 0, 0, 1099, 1100,
7, 10, 0, 0, 1100, 1101, 7, 21, 0, 0, 1101, 1102, 7, 11, 0, 0, 1102, 1103,
7, 0, 0, 0, 1103, 1104, 7, 5, 0, 0, 1104, 1105, 7, 10, 0, 0, 1105, 244,
1, 0, 0, 0, 1106, 1107, 7, 3, 0, 0, 1107, 1108, 7, 10, 0, 0, 1108, 1109,
7, 14, 0, 0, 1109, 1110, 7, 4, 0, 0, 1110, 1111, 7, 3, 0, 0, 1111, 1112,
7, 6, 0, 0, 1112, 1113, 7, 5, 0, 0, 1113, 1114, 7, 4, 0, 0, 1114, 246,
1, 0, 0, 0, 1115, 1116, 7, 3, 0, 0, 1116, 1117, 7, 10, 0, 0, 1117, 1118,
7, 4, 0, 0, 1118, 1119, 7, 16, 0, 0, 1119, 1120, 7, 3, 0, 0, 1120, 1121,
7, 7, 0, 0, 1121, 1122, 7, 6, 0, 0, 1122, 1123, 7, 7, 0, 0, 1123, 1124,
7, 18, 0, 0, 1124, 248, 1, 0, 0, 0, 1125, 1126, 7, 3, 0, 0, 1126, 1127,
7, 6, 0, 0, 1127, 1128, 7, 18, 0, 0, 1128, 1129, 7, 15, 0, 0, 1129, 1130,
7, 4, 0, 0, 1130, 250, 1, 0, 0, 0, 1131, 1132, 7, 3, 0, 0, 1132, 1133,
7, 2, 0, 0, 1133, 1134, 7, 11, 0, 0, 1134, 1135, 7, 11, 0, 0, 1135, 1136,
7, 1, 0, 0, 1136, 1137, 7, 0, 0, 0, 1137, 1138, 7, 5, 0, 0, 1138, 1139,
7, 20, 0, 0, 1139, 252, 1, 0, 0, 0, 1140, 1141, 7, 3, 0, 0, 1141, 1142,
7, 2, 0, 0, 1142, 1143, 7, 19, 0, 0, 1143, 254, 1, 0, 0, 0, 1144, 1145,
7, 3, 0, 0, 1145, 1146, 7, 2, 0, 0, 1146, 1147, 7, 19, 0, 0, 1147, 1148,
7, 14, 0, 0, 1148, 256, 1, 0, 0, 0, 1149, 1150, 7, 14, 0, 0, 1150, 1151,
7, 0, 0, 0, 1151, 1152, 7, 23, 0, 0, 1152, 1153, 7, 10, 0, 0, 1153, 1154,
7, 21, 0, 0, 1154, 1155, 7, 2, 0, 0, 1155, 1156, 7, 6, 0, 0, 1156, 1157,
7, 7, 0, 0, 1157, 1158, 7, 4, 0, 0, 1158, 258, 1, 0, 0, 0, 1159, 1160,
7, 14, 0, 0, 1160, 1161, 7, 10, 0, 0, 1161, 1162, 7, 11, 0, 0, 1162, 1163,
7, 10, 0, 0, 1163, 1164, 7, 5, 0, 0, 1164, 1165, 7, 4, 0, 0, 1165, 260,
1, 0, 0, 0, 1166, 1167, 7, 14, 0, 0, 1167, 1168, 7, 10, 0, 0, 1168, 1169,
7, 4, 0, 0, 1169, 262, 1, 0, 0, 0, 1170, 1171, 7, 4, 0, 0, 1171, 1172,
7, 0, 0, 0, 1172, 1173, 7, 1, 0, 0, 1173, 1174, 7, 11, 0, 0, 1174, 1175,
7, 10, 0, 0, 1175, 264, 1, 0, 0, 0, 1176, 1177, 7, 4, 0, 0, 1177, 1178,
7, 10, 0, 0, 1178, 1179, 7, 17, 0, 0, 1179, 1180, 7, 21, 0, 0, 1180, 266,
1, 0, 0, 0, 1181, 1182, 7, 4, 0, 0, 1182, 1183, 7, 10, 0, 0, 1183, 1184,
7, 17, 0, 0, 1184, 1185, 7, 21, 0, 0, 1185, 1186, 7, 2, 0, 0, 1186, 1187,
7, 3, 0, 0, 1187, 1188, 7, 0, 0, 0, 1188, 1189, 7, 3, 0, 0, 1189, 1190,
7, 12, 0, 0, 1190, 268, 1, 0, 0, 0, 1191, 1192, 7, 4, 0, 0, 1192, 1193,
7, 15, 0, 0, 1193, 1194, 7, 10, 0, 0, 1194, 1195, 7, 7, 0, 0, 1195, 270,
1, 0, 0, 0, 1196, 1197, 7, 4, 0, 0, 1197, 1198, 7, 2, 0, 0, 1198, 272,
1, 0, 0, 0, 1199, 1200, 7, 4, 0, 0, 1200, 1201, 7, 3, 0, 0, 1201, 1202,
7, 0, 0, 0, 1202, 1203, 7, 7, 0, 0, 1203, 1204, 7, 14, 0, 0, 1204, 1205,
7, 0, 0, 0, 1205, 1206, 7, 5, 0, 0, 1206, 1207, 7, 4, 0, 0, 1207, 1208,
7, 6, 0, 0, 1208, 1209, 7, 2, 0, 0, 1209, 1210, 7, 7, 0, 0, 1210, 274,
1, 0, 0, 0, 1211, 1212, 7, 4, 0, 0, 1212, 1213, 7, 3, 0, 0, 1213, 1214,
7, 6, 0, 0, 1214, 1215, 7, 18, 0, 0, 1215, 1216, 7, 18, 0, 0, 1216, 1217,
7, 10, 0, 0, 1217, 1218, 7, 3, 0, 0, 1218, 276, 1, 0, 0, 0, 1219, 1220,
7, 16, 0, 0, 1220, 1221, 7, 7, 0, 0, 1221, 1222, 7, 6, 0, 0, 1222, 1223,
7, 2, 0, 0, 1223, 1224, 7, 7, 0, 0, 1224, 278, 1, 0, 0, 0, 1225, 1226,
7, 16, 0, 0, 1226, 1227, 7, 7, 0, 0, 1227, 1228, 7, 6, 0, 0, 1228, 1229,
7, 25, 0, 0, 1229, 1230, 7, 16, 0, 0, 1230, 1231, 7, 10, 0, 0, 1231, 280,
1, 0, 0, 0, 1232, 1233, 7, 16, 0, 0, 1233, 1234, 7, 21, 0, 0, 1234, 1235,
7, 8, 0, 0, 1235, 1236, 7, 0, 0, 0, 1236, 1237, 7, 4, 0, 0, 1237, 1238,
7, 10, 0, 0, 1238, 282, 1, 0, 0, 0, 1239, 1240, 7, 16, 0, 0, 1240, 1241,
7, 14, 0, 0, 1241, 1242, 7, 6, 0, 0, 1242, 1243, 7, 7, 0, 0, 1243, 1244,
7, 18, 0, 0, 1244, 284, 1, 0, 0, 0, 1245, 1246, 7, 23, 0, 0, 1246, 1247,
7, 0, 0, 0, 1247, 1248, 7, 5, 0, 0, 1248, 1249, 7, 16, 0, 0, 1249, 1250,
7, 16, 0, 0, 1250, 1251, 7, 17, 0, 0, 1251, 286, 1, 0, 0, 0, 1252, 1253,
7, 23, 0, 0, 1253, 1254, 7, 0, 0, 0, 1254, 1255, 7, 11, 0, 0, 1255, 1256,
7, 16, 0, 0, 1256, 1257, 7, 10, 0, 0, 1257, 1258, 7, 14, 0, 0, 1258, 288,
1, 0, 0, 0, 1259, 1260, 7, 23, 0, 0, 1260, 1261, 7, 6, 0, 0, 1261, 1262,
7, 10, 0, 0, 1262, 1263, 7, 19, 0, 0, 1263, 290, 1, 0, 0, 0, 1264, 1265,
7, 23, 0, 0, 1265, 1266, 7, 6, 0, 0, 1266, 1267, 7, 3, 0, 0, 1267, 1268,
7, 4, 0, 0, 1268, 1269, 7, 16, 0, 0, 1269, 1270, 7, 0, 0, 0, 1270, 1271,
7, 11, 0, 0, 1271, 292, 1, 0, 0, 0, 1272, 1273, 7, 19, 0, 0, 1273, 1274,
7, 15, 0, 0, 1274, 1275, 7, 10, 0, 0, 1275, 1276, 7, 7, 0, 0, 1276, 294,
1, 0, 0, 0, 1277, 1278, 7, 19, 0, 0, 1278, 1279, 7, 15, 0, 0, 1279, 1280,
7, 10, 0, 0, 1280, 1281, 7, 3, 0, 0, 1281, 1282, 7, 10, 0, 0, 1282, 296,
1, 0, 0, 0, 1283, 1284, 7, 19, 0, 0, 1284, 1285, 7, 6, 0, 0, 1285, 1286,
7, 4, 0, 0, 1286, 1287, 7, 15, 0, 0, 1287, 298, 1, 0, 0, 0, 1288, 1289,
7, 19, 0, 0, 1289, 1290, 7, 6, 0, 0, 1290, 1291, 7, 4, 0, 0, 1291, 1292,
7, 15, 0, 0, 1292, 1293, 7, 2, 0, 0, 1293, 1294, 7, 16, 0, 0, 1294, 1295,
7, 4, 0, 0, 1295, 300, 1, 0, 0, 0, 1296, 1297, 7, 9, 0, 0, 1297, 1298,
7, 6, 0, 0, 1298, 1299, 7, 3, 0, 0, 1299, 1300, 7, 14, 0, 0, 1300, 1301,
7, 4, 0, 0, 1301, 1302, 5, 95, 0, 0, 1302, 1303, 7, 23, 0, 0, 1303, 1304,
7, 0, 0, 0, 1304, 1305, 7, 11, 0, 0, 1305, 1306, 7, 16, 0, 0, 1306, 1307,
7, 10, 0, 0, 1307, 302, 1, 0, 0, 0, 1308, 1309, 7, 2, 0, 0, 1309, 1310,
7, 23, 0, 0, 1310, 1311, 7, 10, 0, 0, 1311, 1312, 7, 3, 0, 0, 1312, 304,
1, 0, 0, 0, 1313, 1314, 7, 21, 0, 0, 1314, 1315, 7, 0, 0, 0, 1315, 1316,
7, 3, 0, 0, 1316, 1317, 7, 4, 0, 0, 1317, 1318, 7, 6, 0, 0, 1318, 1319,
7, 4, 0, 0, 1319, 1320, 7, 6, 0, 0, 1320, 1321, 7, 2, 0, 0, 1321, 1322,
7, 7, 0, 0, 1322, 306, 1, 0, 0, 0, 1323, 1324, 7, 3, 0, 0, 1324, 1325,
7, 0, 0, 0, 1325, 1326, 7, 7, 0, 0, 1326, 1327, 7, 18, 0, 0, 1327, 1328,
7, 10, 0, 0, 1328, 308, 1, 0, 0, 0, 1329, 1330, 7, 21, 0, 0, 1330, 1331,
7, 3, 0, 0, 1331, 1332, 7, 10, 0, 0, 1332, 1333, 7, 5, 0, 0, 1333, 1334,
7, 10, 0, 0, 1334, 1335, 7, 8, 0, 0, 1335, 1336, 7, 6, 0, 0, 1336, 1337,
7, 7, 0, 0, 1337, 1338, 7, 18, 0, 0, 1338, 310, 1, 0, 0, 0, 1339, 1340,
7, 16, 0, 0, 1340, 1341, 7, 7, 0, 0, 1341, 1342, 7, 1, 0, 0, 1342, 1343,
7, 2, 0, 0, 1343, 1344, 7, 16, 0, 0, 1344, 1345, 7, 7, 0, 0, 1345, 1346,
7, 8, 0, 0, 1346, 1347, 7, 10, 0, 0, 1347, 1348, 7, 8, 0, 0, 1348, 312,
1, 0, 0, 0, 1349, 1350, 7, 5, 0, 0, 1350, 1351, 7, 16, 0, 0, 1351, 1352,
7, 3, 0, 0, 1352, 1353, 7, 3, 0, 0, 1353, 1354, 7, 10, 0, 0, 1354, 1355,
7, 7, 0, 0, 1355, 1356, 7, 4, 0, 0, 1356, 314, 1, 0, 0, 0, 1357, 1358,
7, 9, 0, 0, 1358, 1359, 7, 2, 0, 0, 1359, 1360, 7, 11, 0, 0, 1360, 1361,
7, 11, 0, 0, 1361, 1362, 7, 2, 0, 0, 1362, 1363, 7, 19, 0, 0, 1363, 1364,
7, 6, 0, 0, 1364, 1365, 7, 7, 0, 0, 1365, 1366, 7, 18, 0, 0, 1366, 316,
1, 0, 0, 0, 1367, 1368, 7, 5, 0, 0, 1368, 1369, 7, 16, 0, 0, 1369, 1370,
7, 17, 0, 0, 1370, 1371, 7, 10, 0, 0, 1371, 1372, 5, 95, 0, 0, 1372, 1373,
7, 8, 0, 0, 1373, 1374, 7, 6, 0, 0, 1374, 1375, 7, 14, 0, 0, 1375, 1376,
7, 4, 0, 0, 1376, 318, 1, 0, 0, 0, 1377, 1378, 7, 8, 0, 0, 1378, 1379,
7, 10, 0, 0, 1379, 1380, 7, 7, 0, 0, 1380, 1381, 7, 14, 0, 0, 1381, 1382,
7, 10, 0, 0, 1382, 1383, 5, 95, 0, 0, 1383, 1384, 7, 3, 0, 0, 1384, 1385,
7, 0, 0, 0, 1385, 1386, 7, 7, 0, 0, 1386, 1387, 7, 20, 0, 0, 1387, 320,
1, 0, 0, 0, 1388, 1389, 7, 11, 0, 0, 1389, 1390, 7, 0, 0, 0, 1390, 1391,
7, 18, 0, 0, 1391, 322, 1, 0, 0, 0, 1392, 1393, 7, 11, 0, 0, 1393, 1394,
7, 0, 0, 0, 1394, 1395, 7, 14, 0, 0, 1395, 1396, 7, 4, 0, 0, 1396, 1397,
5, 95, 0, 0, 1397, 1398, 7, 23, 0, 0, 1398, 1399, 7, 0, 0, 0, 1399, 1400,
7, 11, 0, 0, 1400, 1401, 7, 16, 0, 0, 1401, 1402, 7, 10, 0, 0, 1402, 324,
1, 0, 0, 0, 1403, 1404, 7, 11, 0, 0, 1404, 1405, 7, 10, 0, 0, 1405, 1406,
7, 0, 0, 0, 1406, 1407, 7, 8, 0, 0, 1407, 326, 1, 0, 0, 0, 1408, 1409,
7, 7, 0, 0, 1409, 1410, 7, 4, 0, 0, 1410, 1411, 7, 15, 0, 0, 1411, 1412,
5, 95, 0, 0, 1412, 1413, 7, 23, 0, 0, 1413, 1414, 7, 0, 0, 0, 1414, 1415,
7, 11, 0, 0, 1415, 1416, 7, 16, 0, 0, 1416, 1417, 7, 10, 0, 0, 1417, 328,
1, 0, 0, 0, 1418, 1419, 7, 7, 0, 0, 1419, 1420, 7, 4, 0, 0, 1420, 1421,
7, 6, 0, 0, 1421, 1422, 7, 11, 0, 0, 1422, 1423, 7, 10, 0, 0, 1423, 330,
1, 0, 0, 0, 1424, 1425, 7, 21, 0, 0, 1425, 1426, 7, 10, 0, 0, 1426, 1427,
7, 3, 0, 0, 1427, 1428, 7, 5, 0, 0, 1428, 1429, 7, 10, 0, 0, 1429, 1430,
7, 7, 0, 0, 1430, 1431, 7, 4, 0, 0, 1431, 1432, 5, 95, 0, 0, 1432, 1433,
7, 3, 0, 0, 1433, 1434, 7, 0, 0, 0, 1434, 1435, 7, 7, 0, 0, 1435, 1436,
7, 20, 0, 0, 1436, 332, 1, 0, 0, 0, 1437, 1438, 7, 3, 0, 0, 1438, 1439,
7, 0, 0, 0, 1439, 1440, 7, 7, 0, 0, 1440, 1441, 7, 20, 0, 0, 1441, 334,
1, 0, 0, 0, 1442, 1443, 7, 3, 0, 0, 1443, 1444, 7, 2, 0, 0, 1444, 1445,
7, 19, 0, 0, 1445, 1446, 5, 95, 0, 0, 1446, 1447, 7, 7, 0, 0, 1447, 1448,
7, 16, 0, 0, 1448, 1449, 7, 17, 0, 0, 1449, 1450, 7, 1, 0, 0, 1450, 1451,
7, 10, 0, 0, 1451, 1452, 7, 3, 0, 0, 1452, 336, 1, 0, 0, 0, 1453, 1454,
7, 18, 0, 0, 1454, 1455, 7, 10, 0, 0, 1455, 1456, 7, 7, 0, 0, 1456, 1457,
7, 10, 0, 0, 1457, 1458, 7, 3, 0, 0, 1458, 1459, 7, 0, 0, 0, 1459, 1460,
7, 4, 0, 0, 1460, 1461, 7, 10, 0, 0, 1461, 1462, 7, 8, 0, 0, 1462, 338,
1, 0, 0, 0, 1463, 1464, 7, 0, 0, 0, 1464, 1465, 7, 11, 0, 0, 1465, 1466,
7, 19, 0, 0, 1466, 1467, 7, 0, 0, 0, 1467, 1468, 7, 12, 0, 0, 1468, 1469,
7, 14, 0, 0, 1469, 340, 1, 0, 0, 0, 1470, 1471, 7, 14, 0, 0, 1471, 1472,
7, 4, 0, 0, 1472, 1473, 7, 2, 0, 0, 1473, 1474, 7, 3, 0, 0, 1474, 1475,
7, 10, 0, 0, 1475, 1476, 7, 8, 0, 0, 1476, 342, 1, 0, 0, 0, 1477, 1478,
7, 4, 0, 0, 1478, 1479, 7, 3, 0, 0, 1479, 1480, 7, 16, 0, 0, 1480, 1481,
7, 10, 0, 0, 1481, 344, 1, 0, 0, 0, 1482, 1483, 7, 9, 0, 0, 1483, 1484,
7, 0, 0, 0, 1484, 1485, 7, 11, 0, 0, 1485, 1486, 7, 14, 0, 0, 1486, 1487,
7, 10, 0, 0, 1487, 346, 1, 0, 0, 0, 1488, 1489, 7, 19, 0, 0, 1489, 1490,
7, 6, 0, 0, 1490, 1491, 7, 7, 0, 0, 1491, 1492, 7, 8, 0, 0, 1492, 1493,
7, 2, 0, 0, 1493, 1494, 7, 19, 0, 0, 1494, 348, 1, 0, 0, 0, 1495, 1496,
7, 7, 0, 0, 1496, 1497, 7, 16, 0, 0, 1497, 1498, 7, 11, 0, 0, 1498, 1499,
7, 11, 0, 0, 1499, 1500, 7, 14, 0, 0, 1500, 350, 1, 0, 0, 0, 1501, 1502,
7, 9, 0, 0, 1502, 1503, 7, 6, 0, 0, 1503, 1504, 7, 3, 0, 0, 1504, 1505,
7, 14, 0, 0, 1505, 1506, 7, 4, 0, 0, 1506, 352, 1, 0, 0, 0, 1507, 1508,
7, 11, 0, 0, 1508, 1509, 7, 0, 0, 0, 1509, 1510, 7, 14, 0, 0, 1510, 1511,
7, 4, 0, 0, 1511, 354, 1, 0, 0, 0, 1512, 1513, 7, 9, 0, 0, 1513, 1514,
7, 6, 0, 0, 1514, 1515, 7, 11, 0, 0, 1515, 1516, 7, 4, 0, 0, 1516, 1517,
7, 10, 0, 0, 1517, 1518, 7, 3, 0, 0, 1518, 356, 1, 0, 0, 0, 1519, 1520,
7, 18, 0, 0, 1520, 1521, 7, 3, 0, 0, 1521, 1522, 7, 2, 0, 0, 1522, 1523,
7, 16, 0, 0, 1523, 1524, 7, 21, 0, 0, 1524, 1525, 7, 14, 0, 0, 1525, 358,
1, 0, 0, 0, 1526, 1527, 7, 10, 0, 0, 1527, 1528, 7, 22, 0, 0, 1528, 1529,
7, 5, 0, 0, 1529, 1530, 7, 11, 0, 0, 1530, 1531, 7, 16, 0, 0, 1531, 1532,
7, 8, 0, 0, 1532, 1533, 7, 10, 0, 0, 1533, 360, 1, 0, 0, 0, 1534, 1535,
7, 4, 0, 0, 1535, 1536, 7, 6, 0, 0, 1536, 1537, 7, 10, 0, 0, 1537, 1538,
7, 14, 0, 0, 1538, 362, 1, 0, 0, 0, 1539, 1540, 7, 2, 0, 0, 1540, 1541,
7, 4, 0, 0, 1541, 1542, 7, 15, 0, 0, 1542, 1543, 7, 10, 0, 0, 1543, 1544,
7, 3, 0, 0, 1544, 1545, 7, 14, 0, 0, 1545, 364, 1, 0, 0, 0, 1546, 1547,
7, 8, 0, 0, 1547, 1548, 7, 2, 0, 0, 1548, 366, 1, 0, 0, 0, 1549, 1550,
7, 7, 0, 0, 1550, 1551, 7, 2, 0, 0, 1551, 1552, 7, 4, 0, 0, 1552, 1553,
7, 15, 0, 0, 1553, 1554, 7, 6, 0, 0, 1554, 1555, 7, 7, 0, 0, 1555, 1556,
7, 18, 0, 0, 1556, 368, 1, 0, 0, 0, 1557, 1563, 5, 34, 0, 0, 1558, 1562,
8, 26, 0, 0, 1559, 1560, 5, 34, 0, 0, 1560, 1562, 5, 34, 0, 0, 1561, 1558,
1, 0, 0, 0, 1561, 1559, 1, 0, 0, 0, 1562, 1565, 1, 0, 0, 0, 1563, 1561,
1, 0, 0, 0, 1563, 1564, 1, 0, 0, 0, 1564, 1566, 1, 0, 0, 0, 1565, 1563,
1, 0, 0, 0, 1566, 1593, 5, 34, 0, 0, 1567, 1573, 5, 96, 0, 0, 1568, 1572,
8, 27, 0, 0, 1569, 1570, 5, 96, 0, 0, 1570, 1572, 5, 96, 0, 0, 1571, 1568,
1, 0, 0, 0, 1571, 1569, 1, 0, 0, 0, 1572, 1575, 1, 0, 0, 0, 1573, 1571,
1, 0, 0, 0, 1573, 1574, 1, 0, 0, 0, 1574, 1576, 1, 0, 0, 0, 1575, 1573,
1, 0, 0, 0, 1576, 1593, 5, 96, 0, 0, 1577, 1581, 5, 91, 0, 0, 1578, 1580,
8, 28, 0, 0, 1579, 1578, 1, 0, 0, 0, 1580, 1583, 1, 0, 0, 0, 1581, 1579,
1, 0, 0, 0, 1581, 1582, 1, 0, 0, 0, 1582, 1584, 1, 0, 0, 0, 1583, 1581,
1, 0, 0, 0, 1584, 1593, 5, 93, 0, 0, 1585, 1589, 7, 29, 0, 0, 1586, 1588,
7, 30, 0, 0, 1587, 1586, 1, 0, 0, 0, 1588, 1591, 1, 0, 0, 0, 1589, 1587,
1, 0, 0, 0, 1589, 1590, 1, 0, 0, 0, 1590, 1593, 1, 0, 0, 0, 1591, 1589,
1, 0, 0, 0, 1592, 1557, 1, 0, 0, 0, 1592, 1567, 1, 0, 0, 0, 1592, 1577,
1, 0, 0, 0, 1592, 1585, 1, 0, 0, 0, 1593, 370, 1, 0, 0, 0, 1594, 1596,
3, 389, 194, 0, 1595, 1594, 1, 0, 0, 0, 1596, 1597, 1, 0, 0, 0, 1597, 1595,
1, 0, 0, 0, 1597, 1598, 1, 0, 0, 0, 1598, 1606, 1, 0, 0, 0, 1599, 1603,
5, 46, 0, 0, 1600, 1602, 3, 389, 194, 0, 1601, 1600, 1, 0, 0, 0, 1602,
1605, 1, 0, 0, 0, 1603, 1601, 1, 0, 0, 0, 1603, 1604, 1, 0, 0, 0, 1604,
1607, 1, 0, 0, 0, 1605, 1603, 1, 0, 0, 0, 1606, 1599, 1, 0, 0, 0, 1606,
1607, 1, 0, 0, 0, 1607, 1615, 1, 0, 0, 0, 1608, 1610, 5, 46, 0, 0, 1609,
1611, 3, 389, 194, 0, 1610, 1609, 1, 0, 0, 0, 1611, 1612, 1, 0, 0, 0, 1612,
1610, 1, 0, 0, 0, 1612, 1613, 1, 0, 0, 0, 1613, 1615, 1, 0, 0, 0, 1614,
1595, 1, 0, 0, 0, 1614, 1608, 1, 0, 0, 0, 1615, 1625, 1, 0, 0, 0, 1616,
1618, 7, 10, 0, 0, 1617, 1619, 7, 31, 0, 0, 1618, 1617, 1, 0, 0, 0, 1618,
1619, 1, 0, 0, 0, 1619, 1621, 1, 0, 0, 0, 1620, 1622, 3, 389, 194, 0, 1621,
1620, 1, 0, 0, 0, 1622, 1623, 1, 0, 0, 0, 1623, 1621, 1, 0, 0, 0, 1623,
1624, 1, 0, 0, 0, 1624, 1626, 1, 0, 0, 0, 1625, 1616, 1, 0, 0, 0, 1625,
1626, 1, 0, 0, 0, 1626, 1636, 1, 0, 0, 0, 1627, 1628, 5, 48, 0, 0, 1628,
1629, 7, 22, 0, 0, 1629, 1631, 1, 0, 0, 0, 1630, 1632, 3, 387, 193, 0,
1631, 1630, 1, 0, 0, 0, 1632, 1633, 1, 0, 0, 0, 1633, 1631, 1, 0, 0, 0,
1633, 1634, 1, 0, 0, 0, 1634, 1636, 1, 0, 0, 0, 1635, 1614, 1, 0, 0, 0,
1635, 1627, 1, 0, 0, 0, 1636, 372, 1, 0, 0, 0, 1637, 1641, 5, 63, 0, 0,
1638, 1640, 3, 389, 194, 0, 1639, 1638, 1, 0, 0, 0, 1640, 1643, 1, 0, 0,
0, 1641, 1639, 1, 0, 0, 0, 1641, 1642, 1, 0, 0, 0, 1642, 1647, 1, 0, 0,
0, 1643, 1641, 1, 0, 0, 0, 1644, 1645, 7, 32, 0, 0, 1645, 1647, 3, 369,
184, 0, 1646, 1637, 1, 0, 0, 0, 1646, 1644, 1, 0, 0, 0, 1647, 374, 1, 0,
0, 0, 1648, 1654, 5, 39, 0, 0, 1649, 1653, 8, 33, 0, 0, 1650, 1651, 5,
39, 0, 0, 1651, 1653, 5, 39, 0, 0, 1652, 1649, 1, 0, 0, 0, 1652, 1650,
1, 0, 0, 0, 1653, 1656, 1, 0, 0, 0, 1654, 1652, 1, 0, 0, 0, 1654, 1655,
1, 0, 0, 0, 1655, 1657, 1, 0, 0, 0, 1656, 1654, 1, 0, 0, 0, 1657, 1658,
5, 39, 0, 0, 1658, 376, 1, 0, 0, 0, 1659, 1660, 7, 22, 0, 0, 1660, 1661,
3, 375, 187, 0, 1661, 378, 1, 0, 0, 0, 1662, 1663, 5, 45, 0, 0, 1663, 1664,
5, 45, 0, 0, 1664, 1668, 1, 0, 0, 0, 1665, 1667, 8, 34, 0, 0, 1666, 1665,
1, 0, 0, 0, 1667, 1670, 1, 0, 0, 0, 1668, 1666, 1, 0, 0, 0, 1668, 1669,
1, 0, 0, 0, 1669, 1676, 1, 0, 0, 0, 1670, 1668, 1, 0, 0, 0, 1671, 1673,
5, 13, 0, 0, 1672, 1671, 1, 0, 0, 0, 1672, 1673, 1, 0, 0, 0, 1673, 1674,
1, 0, 0, 0, 1674, 1677, 5, 10, 0, 0, 1675, 1677, 5, 0, 0, 1, 1676, 1672,
1, 0, 0, 0, 1676, 1675, 1, 0, 0, 0, 1677, 1678, 1, 0, 0, 0, 1678, 1679,
6, 189, 0, 0, 1679, 380, 1, 0, 0, 0, 1680, 1681, 5, 47, 0, 0, 1681, 1682,
5, 42, 0, 0, 1682, 1686, 1, 0, 0, 0, 1683, 1685, 9, 0, 0, 0, 1684, 1683,
1, 0, 0, 0, 1685, 1688, 1, 0, 0, 0, 1686, 1687, 1, 0, 0, 0, 1686, 1684,
1, 0, 0, 0, 1687, 1689, 1, 0, 0, 0, 1688, 1686, 1, 0, 0, 0, 1689, 1690,
5, 42, 0, 0, 1690, 1691, 5, 47, 0, 0, 1691, 1692, 1, 0, 0, 0, 1692, 1693,
6, 190, 0, 0, 1693, 382, 1, 0, 0, 0, 1694, 1695, 7, 35, 0, 0, 1695, 1696,
1, 0, 0, 0, 1696, 1697, 6, 191, 0, 0, 1697, 384, 1, 0, 0, 0, 1698, 1699,
9, 0, 0, 0, 1699, 386, 1, 0, 0, 0, 1700, 1701, 7, 36, 0, 0, 1701, 388,
1, 0, 0, 0, 1702, 1703, 7, 37, 0, 0, 1703, 390, 1, 0, 0, 0, 26, 0, 1561,
1563, 1571, 1573, 1581, 1589, 1592, 1597, 1603, 1606, 1612, 1614, 1618,
1623, 1625, 1633, 1635, 1641, 1646, 1652, 1654, 1668, 1672, 1676, 1686,
1, 0, 1, 0,
}
deserializer := antlr.NewATNDeserializer(nil)
staticData.atn = deserializer.Deserialize(staticData.serializedATN)
atn := staticData.atn
staticData.decisionToDFA = make([]*antlr.DFA, len(atn.DecisionToState))
decisionToDFA := staticData.decisionToDFA
for index, state := range atn.DecisionToState {
decisionToDFA[index] = antlr.NewDFA(state, index)
}
}
// LexerInit initializes any static state used to implement Lexer. By default the
// static state used to implement the lexer is lazily initialized during the first call to
// NewLexer(). You can call this function if you wish to initialize the static state ahead
// of time.
func LexerInit() {
staticData := &LexerLexerStaticData
staticData.once.Do(lexerLexerInit)
}
// NewLexer produces a new lexer instance for the optional input antlr.CharStream.
func NewLexer(input antlr.CharStream) *Lexer {
LexerInit()
l := new(Lexer)
l.BaseLexer = antlr.NewBaseLexer(input)
staticData := &LexerLexerStaticData
l.Interpreter = antlr.NewLexerATNSimulator(l, staticData.atn, staticData.decisionToDFA, staticData.PredictionContextCache)
l.channelNames = staticData.ChannelNames
l.modeNames = staticData.ModeNames
l.RuleNames = staticData.RuleNames
l.LiteralNames = staticData.LiteralNames
l.SymbolicNames = staticData.SymbolicNames
l.GrammarFileName = "Lexer.g4"
// TODO: l.EOF = antlr.TokenEOF
return l
}
// Lexer tokens.
const (
LexerSCOL = 1
LexerDOT = 2
LexerOPEN_PAR = 3
LexerCLOSE_PAR = 4
LexerCOMMA = 5
LexerASSIGN = 6
LexerSTAR = 7
LexerPLUS = 8
LexerMINUS = 9
LexerTILDE = 10
LexerPIPE2 = 11
LexerDIV = 12
LexerMOD = 13
LexerLT2 = 14
LexerGT2 = 15
LexerAMP = 16
LexerPIPE = 17
LexerLT = 18
LexerLT_EQ = 19
LexerGT = 20
LexerGT_EQ = 21
LexerEQ = 22
LexerNOT_EQ1 = 23
LexerNOT_EQ2 = 24
LexerABORT_ = 25
LexerACTION_ = 26
LexerADD_ = 27
LexerAFTER_ = 28
LexerALL_ = 29
LexerALTER_ = 30
LexerANALYZE_ = 31
LexerAND_ = 32
LexerAS_ = 33
LexerASC_ = 34
LexerATTACH_ = 35
LexerAUTOINCREMENT_ = 36
LexerBEFORE_ = 37
LexerBEGIN_ = 38
LexerBETWEEN_ = 39
LexerBY_ = 40
LexerCASCADE_ = 41
LexerCASE_ = 42
LexerCAST_ = 43
LexerCHECK_ = 44
LexerCOLLATE_ = 45
LexerCOLUMN_ = 46
LexerCOMMIT_ = 47
LexerCONFLICT_ = 48
LexerCONSTRAINT_ = 49
LexerCREATE_ = 50
LexerCROSS_ = 51
LexerCURRENT_DATE_ = 52
LexerCURRENT_TIME_ = 53
LexerCURRENT_TIMESTAMP_ = 54
LexerDATABASE_ = 55
LexerDEFAULT_ = 56
LexerDEFERRABLE_ = 57
LexerDEFERRED_ = 58
LexerDELETE_ = 59
LexerDESC_ = 60
LexerDETACH_ = 61
LexerDISTINCT_ = 62
LexerDROP_ = 63
LexerEACH_ = 64
LexerELSE_ = 65
LexerEND_ = 66
LexerESCAPE_ = 67
LexerEXCEPT_ = 68
LexerEXCLUSIVE_ = 69
LexerEXISTS_ = 70
LexerEXPLAIN_ = 71
LexerFAIL_ = 72
LexerFOR_ = 73
LexerFOREIGN_ = 74
LexerFROM_ = 75
LexerFULL_ = 76
LexerGLOB_ = 77
LexerGROUP_ = 78
LexerHAVING_ = 79
LexerIF_ = 80
LexerIGNORE_ = 81
LexerIMMEDIATE_ = 82
LexerIN_ = 83
LexerINDEX_ = 84
LexerINDEXED_ = 85
LexerINITIALLY_ = 86
LexerINNER_ = 87
LexerINSERT_ = 88
LexerINSTEAD_ = 89
LexerINTERSECT_ = 90
LexerINTO_ = 91
LexerIS_ = 92
LexerISNULL_ = 93
LexerJOIN_ = 94
LexerKEY_ = 95
LexerLEFT_ = 96
LexerLIKE_ = 97
LexerLIMIT_ = 98
LexerMATCH_ = 99
LexerNATURAL_ = 100
LexerNO_ = 101
LexerNOT_ = 102
LexerNOTNULL_ = 103
LexerNULL_ = 104
LexerOF_ = 105
LexerOFFSET_ = 106
LexerON_ = 107
LexerOR_ = 108
LexerORDER_ = 109
LexerOUTER_ = 110
LexerPLAN_ = 111
LexerPRAGMA_ = 112
LexerPRIMARY_ = 113
LexerQUERY_ = 114
LexerRAISE_ = 115
LexerRECURSIVE_ = 116
LexerREFERENCES_ = 117
LexerREGEXP_ = 118
LexerREINDEX_ = 119
LexerRELEASE_ = 120
LexerRENAME_ = 121
LexerREPLACE_ = 122
LexerRESTRICT_ = 123
LexerRETURNING_ = 124
LexerRIGHT_ = 125
LexerROLLBACK_ = 126
LexerROW_ = 127
LexerROWS_ = 128
LexerSAVEPOINT_ = 129
LexerSELECT_ = 130
LexerSET_ = 131
LexerTABLE_ = 132
LexerTEMP_ = 133
LexerTEMPORARY_ = 134
LexerTHEN_ = 135
LexerTO_ = 136
LexerTRANSACTION_ = 137
LexerTRIGGER_ = 138
LexerUNION_ = 139
LexerUNIQUE_ = 140
LexerUPDATE_ = 141
LexerUSING_ = 142
LexerVACUUM_ = 143
LexerVALUES_ = 144
LexerVIEW_ = 145
LexerVIRTUAL_ = 146
LexerWHEN_ = 147
LexerWHERE_ = 148
LexerWITH_ = 149
LexerWITHOUT_ = 150
LexerFIRST_VALUE_ = 151
LexerOVER_ = 152
LexerPARTITION_ = 153
LexerRANGE_ = 154
LexerPRECEDING_ = 155
LexerUNBOUNDED_ = 156
LexerCURRENT_ = 157
LexerFOLLOWING_ = 158
LexerCUME_DIST_ = 159
LexerDENSE_RANK_ = 160
LexerLAG_ = 161
LexerLAST_VALUE_ = 162
LexerLEAD_ = 163
LexerNTH_VALUE_ = 164
LexerNTILE_ = 165
LexerPERCENT_RANK_ = 166
LexerRANK_ = 167
LexerROW_NUMBER_ = 168
LexerGENERATED_ = 169
LexerALWAYS_ = 170
LexerSTORED_ = 171
LexerTRUE_ = 172
LexerFALSE_ = 173
LexerWINDOW_ = 174
LexerNULLS_ = 175
LexerFIRST_ = 176
LexerLAST_ = 177
LexerFILTER_ = 178
LexerGROUPS_ = 179
LexerEXCLUDE_ = 180
LexerTIES_ = 181
LexerOTHERS_ = 182
LexerDO_ = 183
LexerNOTHING_ = 184
LexerIDENTIFIER = 185
LexerNUMERIC_LITERAL = 186
LexerBIND_PARAMETER = 187
LexerSTRING_LITERAL = 188
LexerBLOB_LITERAL = 189
LexerSINGLE_LINE_COMMENT = 190
LexerMULTILINE_COMMENT = 191
LexerSPACES = 192
LexerUNEXPECTED_CHAR = 193
)
================================================
FILE: cmd/atlas/internal/sqlparse/sqliteparse/parser.go
================================================
// Code generated from Parser.g4 by ANTLR 4.13.1. DO NOT EDIT.
package sqliteparse // Parser
import (
"fmt"
"strconv"
"sync"
"github.com/antlr4-go/antlr/v4"
)
// Suppress unused import errors
var _ = fmt.Printf
var _ = strconv.Itoa
var _ = sync.Once{}
type Parser struct {
*antlr.BaseParser
}
var ParserParserStaticData struct {
once sync.Once
serializedATN []int32
LiteralNames []string
SymbolicNames []string
RuleNames []string
PredictionContextCache *antlr.PredictionContextCache
atn *antlr.ATN
decisionToDFA []*antlr.DFA
}
func parserParserInit() {
staticData := &ParserParserStaticData
staticData.LiteralNames = []string{
"", "';'", "'.'", "'('", "')'", "','", "'='", "'*'", "'+'", "'-'", "'~'",
"'||'", "'/'", "'%'", "'<<'", "'>>'", "'&'", "'|'", "'<'", "'<='", "'>'",
"'>='", "'=='", "'!='", "'<>'", "'ABORT'", "'ACTION'", "'ADD'", "'AFTER'",
"'ALL'", "'ALTER'", "'ANALYZE'", "'AND'", "'AS'", "'ASC'", "'ATTACH'",
"'AUTOINCREMENT'", "'BEFORE'", "'BEGIN'", "'BETWEEN'", "'BY'", "'CASCADE'",
"'CASE'", "'CAST'", "'CHECK'", "'COLLATE'", "'COLUMN'", "'COMMIT'",
"'CONFLICT'", "'CONSTRAINT'", "'CREATE'", "'CROSS'", "'CURRENT_DATE'",
"'CURRENT_TIME'", "'CURRENT_TIMESTAMP'", "'DATABASE'", "'DEFAULT'",
"'DEFERRABLE'", "'DEFERRED'", "'DELETE'", "'DESC'", "'DETACH'", "'DISTINCT'",
"'DROP'", "'EACH'", "'ELSE'", "'END'", "'ESCAPE'", "'EXCEPT'", "'EXCLUSIVE'",
"'EXISTS'", "'EXPLAIN'", "'FAIL'", "'FOR'", "'FOREIGN'", "'FROM'", "'FULL'",
"'GLOB'", "'GROUP'", "'HAVING'", "'IF'", "'IGNORE'", "'IMMEDIATE'",
"'IN'", "'INDEX'", "'INDEXED'", "'INITIALLY'", "'INNER'", "'INSERT'",
"'INSTEAD'", "'INTERSECT'", "'INTO'", "'IS'", "'ISNULL'", "'JOIN'",
"'KEY'", "'LEFT'", "'LIKE'", "'LIMIT'", "'MATCH'", "'NATURAL'", "'NO'",
"'NOT'", "'NOTNULL'", "'NULL'", "'OF'", "'OFFSET'", "'ON'", "'OR'",
"'ORDER'", "'OUTER'", "'PLAN'", "'PRAGMA'", "'PRIMARY'", "'QUERY'",
"'RAISE'", "'RECURSIVE'", "'REFERENCES'", "'REGEXP'", "'REINDEX'", "'RELEASE'",
"'RENAME'", "'REPLACE'", "'RESTRICT'", "'RETURNING'", "'RIGHT'", "'ROLLBACK'",
"'ROW'", "'ROWS'", "'SAVEPOINT'", "'SELECT'", "'SET'", "'TABLE'", "'TEMP'",
"'TEMPORARY'", "'THEN'", "'TO'", "'TRANSACTION'", "'TRIGGER'", "'UNION'",
"'UNIQUE'", "'UPDATE'", "'USING'", "'VACUUM'", "'VALUES'", "'VIEW'",
"'VIRTUAL'", "'WHEN'", "'WHERE'", "'WITH'", "'WITHOUT'", "'FIRST_VALUE'",
"'OVER'", "'PARTITION'", "'RANGE'", "'PRECEDING'", "'UNBOUNDED'", "'CURRENT'",
"'FOLLOWING'", "'CUME_DIST'", "'DENSE_RANK'", "'LAG'", "'LAST_VALUE'",
"'LEAD'", "'NTH_VALUE'", "'NTILE'", "'PERCENT_RANK'", "'RANK'", "'ROW_NUMBER'",
"'GENERATED'", "'ALWAYS'", "'STORED'", "'TRUE'", "'FALSE'", "'WINDOW'",
"'NULLS'", "'FIRST'", "'LAST'", "'FILTER'", "'GROUPS'", "'EXCLUDE'",
"'TIES'", "'OTHERS'", "'DO'", "'NOTHING'",
}
staticData.SymbolicNames = []string{
"", "SCOL", "DOT", "OPEN_PAR", "CLOSE_PAR", "COMMA", "ASSIGN", "STAR",
"PLUS", "MINUS", "TILDE", "PIPE2", "DIV", "MOD", "LT2", "GT2", "AMP",
"PIPE", "LT", "LT_EQ", "GT", "GT_EQ", "EQ", "NOT_EQ1", "NOT_EQ2", "ABORT_",
"ACTION_", "ADD_", "AFTER_", "ALL_", "ALTER_", "ANALYZE_", "AND_", "AS_",
"ASC_", "ATTACH_", "AUTOINCREMENT_", "BEFORE_", "BEGIN_", "BETWEEN_",
"BY_", "CASCADE_", "CASE_", "CAST_", "CHECK_", "COLLATE_", "COLUMN_",
"COMMIT_", "CONFLICT_", "CONSTRAINT_", "CREATE_", "CROSS_", "CURRENT_DATE_",
"CURRENT_TIME_", "CURRENT_TIMESTAMP_", "DATABASE_", "DEFAULT_", "DEFERRABLE_",
"DEFERRED_", "DELETE_", "DESC_", "DETACH_", "DISTINCT_", "DROP_", "EACH_",
"ELSE_", "END_", "ESCAPE_", "EXCEPT_", "EXCLUSIVE_", "EXISTS_", "EXPLAIN_",
"FAIL_", "FOR_", "FOREIGN_", "FROM_", "FULL_", "GLOB_", "GROUP_", "HAVING_",
"IF_", "IGNORE_", "IMMEDIATE_", "IN_", "INDEX_", "INDEXED_", "INITIALLY_",
"INNER_", "INSERT_", "INSTEAD_", "INTERSECT_", "INTO_", "IS_", "ISNULL_",
"JOIN_", "KEY_", "LEFT_", "LIKE_", "LIMIT_", "MATCH_", "NATURAL_", "NO_",
"NOT_", "NOTNULL_", "NULL_", "OF_", "OFFSET_", "ON_", "OR_", "ORDER_",
"OUTER_", "PLAN_", "PRAGMA_", "PRIMARY_", "QUERY_", "RAISE_", "RECURSIVE_",
"REFERENCES_", "REGEXP_", "REINDEX_", "RELEASE_", "RENAME_", "REPLACE_",
"RESTRICT_", "RETURNING_", "RIGHT_", "ROLLBACK_", "ROW_", "ROWS_", "SAVEPOINT_",
"SELECT_", "SET_", "TABLE_", "TEMP_", "TEMPORARY_", "THEN_", "TO_",
"TRANSACTION_", "TRIGGER_", "UNION_", "UNIQUE_", "UPDATE_", "USING_",
"VACUUM_", "VALUES_", "VIEW_", "VIRTUAL_", "WHEN_", "WHERE_", "WITH_",
"WITHOUT_", "FIRST_VALUE_", "OVER_", "PARTITION_", "RANGE_", "PRECEDING_",
"UNBOUNDED_", "CURRENT_", "FOLLOWING_", "CUME_DIST_", "DENSE_RANK_",
"LAG_", "LAST_VALUE_", "LEAD_", "NTH_VALUE_", "NTILE_", "PERCENT_RANK_",
"RANK_", "ROW_NUMBER_", "GENERATED_", "ALWAYS_", "STORED_", "TRUE_",
"FALSE_", "WINDOW_", "NULLS_", "FIRST_", "LAST_", "FILTER_", "GROUPS_",
"EXCLUDE_", "TIES_", "OTHERS_", "DO_", "NOTHING_", "IDENTIFIER", "NUMERIC_LITERAL",
"BIND_PARAMETER", "STRING_LITERAL", "BLOB_LITERAL", "SINGLE_LINE_COMMENT",
"MULTILINE_COMMENT", "SPACES", "UNEXPECTED_CHAR",
}
staticData.RuleNames = []string{
"parse", "sql_stmt_list", "sql_stmt", "alter_table_stmt", "analyze_stmt",
"attach_stmt", "begin_stmt", "commit_stmt", "rollback_stmt", "savepoint_stmt",
"release_stmt", "create_index_stmt", "indexed_column", "create_table_stmt",
"column_def", "type_name", "column_constraint", "signed_number", "table_constraint",
"foreign_key_clause", "conflict_clause", "create_trigger_stmt", "create_view_stmt",
"create_virtual_table_stmt", "with_clause", "cte_table_name", "recursive_cte",
"common_table_expression", "delete_stmt", "delete_stmt_limited", "detach_stmt",
"drop_stmt", "expr", "raise_function", "literal_value", "insert_stmt",
"returning_clause", "upsert_clause", "pragma_stmt", "pragma_value",
"reindex_stmt", "select_stmt", "join_clause", "select_core", "factored_select_stmt",
"simple_select_stmt", "compound_select_stmt", "table_or_subquery", "result_column",
"join_operator", "join_constraint", "compound_operator", "update_stmt",
"assignment_list", "assignment", "column_name_list", "update_stmt_limited",
"qualified_table_name", "vacuum_stmt", "filter_clause", "window_defn",
"over_clause", "frame_spec", "frame_clause", "simple_function_invocation",
"aggregate_function_invocation", "window_function_invocation", "common_table_stmt",
"order_by_stmt", "limit_stmt", "ordering_term", "asc_desc", "frame_left",
"frame_right", "frame_single", "window_function", "offset", "default_value",
"partition_by", "order_by_expr", "order_by_expr_asc_desc", "expr_asc_desc",
"initial_select", "recursive_select", "unary_operator", "error_message",
"module_argument", "column_alias", "keyword", "name", "function_name",
"schema_name", "table_name", "table_or_index_name", "column_name", "collation_name",
"foreign_table", "index_name", "trigger_name", "view_name", "module_name",
"pragma_name", "savepoint_name", "table_alias", "transaction_name",
"window_name", "alias", "filename", "base_window_name", "simple_func",
"aggregate_func", "table_function_name", "any_name",
}
staticData.PredictionContextCache = antlr.NewPredictionContextCache()
staticData.serializedATN = []int32{
4, 1, 193, 2083, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4,
7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10,
7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7,
15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20,
2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2,
26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31,
7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7,
36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41,
2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2,
47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52,
7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7,
57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62,
2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2,
68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73,
7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7,
78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83,
2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2,
89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94,
7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7,
99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2,
104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7,
108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 1,
0, 5, 0, 228, 8, 0, 10, 0, 12, 0, 231, 9, 0, 1, 0, 1, 0, 1, 1, 5, 1, 236,
8, 1, 10, 1, 12, 1, 239, 9, 1, 1, 1, 1, 1, 4, 1, 243, 8, 1, 11, 1, 12,
1, 244, 1, 1, 5, 1, 248, 8, 1, 10, 1, 12, 1, 251, 9, 1, 1, 1, 5, 1, 254,
8, 1, 10, 1, 12, 1, 257, 9, 1, 1, 2, 1, 2, 1, 2, 3, 2, 262, 8, 2, 3, 2,
264, 8, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
1, 2, 1, 2, 3, 2, 290, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 297, 8,
3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 304, 8, 3, 1, 3, 1, 3, 1, 3, 1,
3, 3, 3, 310, 8, 3, 1, 3, 1, 3, 3, 3, 314, 8, 3, 1, 3, 1, 3, 1, 3, 3, 3,
319, 8, 3, 1, 3, 3, 3, 322, 8, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 329,
8, 4, 1, 4, 3, 4, 332, 8, 4, 1, 5, 1, 5, 3, 5, 336, 8, 5, 1, 5, 1, 5, 1,
5, 1, 5, 1, 6, 1, 6, 3, 6, 344, 8, 6, 1, 6, 1, 6, 3, 6, 348, 8, 6, 3, 6,
350, 8, 6, 1, 7, 1, 7, 3, 7, 354, 8, 7, 1, 8, 1, 8, 3, 8, 358, 8, 8, 1,
8, 1, 8, 3, 8, 362, 8, 8, 1, 8, 3, 8, 365, 8, 8, 1, 9, 1, 9, 1, 9, 1, 10,
1, 10, 3, 10, 372, 8, 10, 1, 10, 1, 10, 1, 11, 1, 11, 3, 11, 378, 8, 11,
1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 384, 8, 11, 1, 11, 1, 11, 1, 11, 3,
11, 389, 8, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11,
398, 8, 11, 10, 11, 12, 11, 401, 9, 11, 1, 11, 1, 11, 1, 11, 3, 11, 406,
8, 11, 1, 12, 1, 12, 3, 12, 410, 8, 12, 1, 12, 1, 12, 3, 12, 414, 8, 12,
1, 12, 3, 12, 417, 8, 12, 1, 13, 1, 13, 3, 13, 421, 8, 13, 1, 13, 1, 13,
1, 13, 1, 13, 3, 13, 427, 8, 13, 1, 13, 1, 13, 1, 13, 3, 13, 432, 8, 13,
1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 439, 8, 13, 10, 13, 12, 13, 442,
9, 13, 1, 13, 1, 13, 5, 13, 446, 8, 13, 10, 13, 12, 13, 449, 9, 13, 1,
13, 1, 13, 1, 13, 3, 13, 454, 8, 13, 1, 13, 1, 13, 3, 13, 458, 8, 13, 1,
14, 1, 14, 3, 14, 462, 8, 14, 1, 14, 5, 14, 465, 8, 14, 10, 14, 12, 14,
468, 9, 14, 1, 15, 4, 15, 471, 8, 15, 11, 15, 12, 15, 472, 1, 15, 1, 15,
1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 485, 8,
15, 1, 16, 1, 16, 3, 16, 489, 8, 16, 1, 16, 1, 16, 1, 16, 3, 16, 494, 8,
16, 1, 16, 3, 16, 497, 8, 16, 1, 16, 3, 16, 500, 8, 16, 1, 16, 1, 16, 1,
16, 3, 16, 505, 8, 16, 1, 16, 3, 16, 508, 8, 16, 1, 16, 1, 16, 1, 16, 1,
16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 522,
8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 529, 8, 16, 1, 16, 1,
16, 1, 16, 1, 16, 1, 16, 3, 16, 536, 8, 16, 3, 16, 538, 8, 16, 1, 17, 3,
17, 541, 8, 17, 1, 17, 1, 17, 1, 18, 1, 18, 3, 18, 547, 8, 18, 1, 18, 1,
18, 1, 18, 3, 18, 552, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 5, 18, 558, 8,
18, 10, 18, 12, 18, 561, 9, 18, 1, 18, 1, 18, 3, 18, 565, 8, 18, 1, 18,
1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 5,
18, 578, 8, 18, 10, 18, 12, 18, 581, 9, 18, 1, 18, 1, 18, 1, 18, 3, 18,
586, 8, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 594, 8, 19,
10, 19, 12, 19, 597, 9, 19, 1, 19, 1, 19, 3, 19, 601, 8, 19, 1, 19, 1,
19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 611, 8, 19, 1, 19,
1, 19, 5, 19, 615, 8, 19, 10, 19, 12, 19, 618, 9, 19, 1, 19, 3, 19, 621,
8, 19, 1, 19, 1, 19, 1, 19, 3, 19, 626, 8, 19, 3, 19, 628, 8, 19, 1, 20,
1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 3, 21, 636, 8, 21, 1, 21, 1, 21, 1,
21, 1, 21, 3, 21, 642, 8, 21, 1, 21, 1, 21, 1, 21, 3, 21, 647, 8, 21, 1,
21, 1, 21, 1, 21, 1, 21, 1, 21, 3, 21, 654, 8, 21, 1, 21, 1, 21, 1, 21,
1, 21, 1, 21, 1, 21, 1, 21, 5, 21, 663, 8, 21, 10, 21, 12, 21, 666, 9,
21, 3, 21, 668, 8, 21, 3, 21, 670, 8, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1,
21, 3, 21, 677, 8, 21, 1, 21, 1, 21, 3, 21, 681, 8, 21, 1, 21, 1, 21, 1,
21, 1, 21, 1, 21, 3, 21, 688, 8, 21, 1, 21, 1, 21, 4, 21, 692, 8, 21, 11,
21, 12, 21, 693, 1, 21, 1, 21, 1, 22, 1, 22, 3, 22, 700, 8, 22, 1, 22,
1, 22, 1, 22, 1, 22, 3, 22, 706, 8, 22, 1, 22, 1, 22, 1, 22, 3, 22, 711,
8, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 5, 22, 718, 8, 22, 10, 22, 12,
22, 721, 9, 22, 1, 22, 1, 22, 3, 22, 725, 8, 22, 1, 22, 1, 22, 1, 22, 1,
23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 736, 8, 23, 1, 23, 1, 23,
1, 23, 3, 23, 741, 8, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1,
23, 5, 23, 750, 8, 23, 10, 23, 12, 23, 753, 9, 23, 1, 23, 1, 23, 3, 23,
757, 8, 23, 1, 24, 1, 24, 3, 24, 761, 8, 24, 1, 24, 1, 24, 1, 24, 1, 24,
1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 775, 8,
24, 10, 24, 12, 24, 778, 9, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 5, 25,
785, 8, 25, 10, 25, 12, 25, 788, 9, 25, 1, 25, 1, 25, 3, 25, 792, 8, 25,
1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 800, 8, 26, 1, 26, 1,
26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 5, 27, 810, 8, 27, 10, 27,
12, 27, 813, 9, 27, 1, 27, 1, 27, 3, 27, 817, 8, 27, 1, 27, 1, 27, 1, 27,
1, 27, 1, 27, 1, 28, 3, 28, 825, 8, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1,
28, 3, 28, 832, 8, 28, 1, 28, 3, 28, 835, 8, 28, 1, 29, 3, 29, 838, 8,
29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 3, 29, 845, 8, 29, 1, 29, 3, 29,
848, 8, 29, 1, 29, 3, 29, 851, 8, 29, 1, 29, 3, 29, 854, 8, 29, 1, 30,
1, 30, 3, 30, 858, 8, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 3,
31, 866, 8, 31, 1, 31, 1, 31, 1, 31, 3, 31, 871, 8, 31, 1, 31, 1, 31, 1,
32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 881, 8, 32, 1, 32, 1, 32,
1, 32, 3, 32, 886, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1,
32, 3, 32, 895, 8, 32, 1, 32, 1, 32, 1, 32, 5, 32, 900, 8, 32, 10, 32,
12, 32, 903, 9, 32, 1, 32, 3, 32, 906, 8, 32, 1, 32, 1, 32, 3, 32, 910,
8, 32, 1, 32, 3, 32, 913, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 5, 32, 919,
8, 32, 10, 32, 12, 32, 922, 9, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1,
32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 934, 8, 32, 1, 32, 3, 32, 937, 8,
32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 945, 8, 32, 1, 32,
1, 32, 1, 32, 1, 32, 1, 32, 4, 32, 952, 8, 32, 11, 32, 12, 32, 953, 1,
32, 1, 32, 3, 32, 958, 8, 32, 1, 32, 1, 32, 1, 32, 3, 32, 963, 8, 32, 1,
32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32,
1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1,
32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 993, 8, 32, 1, 32,
1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1005,
8, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1010, 8, 32, 1, 32, 1, 32, 1, 32, 1,
32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1022, 8, 32, 1, 32,
1, 32, 1, 32, 1, 32, 3, 32, 1028, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1,
32, 3, 32, 1035, 8, 32, 1, 32, 1, 32, 3, 32, 1039, 8, 32, 1, 32, 1, 32,
1, 32, 1, 32, 1, 32, 1, 32, 5, 32, 1047, 8, 32, 10, 32, 12, 32, 1050, 9,
32, 3, 32, 1052, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1058, 8, 32,
1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1064, 8, 32, 1, 32, 1, 32, 1, 32, 1,
32, 1, 32, 5, 32, 1071, 8, 32, 10, 32, 12, 32, 1074, 9, 32, 3, 32, 1076,
8, 32, 1, 32, 1, 32, 3, 32, 1080, 8, 32, 5, 32, 1082, 8, 32, 10, 32, 12,
32, 1085, 9, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 1093,
8, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 3, 35, 1100, 8, 35, 1, 35, 1,
35, 1, 35, 1, 35, 1, 35, 3, 35, 1107, 8, 35, 1, 35, 1, 35, 1, 35, 1, 35,
3, 35, 1113, 8, 35, 1, 35, 1, 35, 1, 35, 3, 35, 1118, 8, 35, 1, 35, 1,
35, 1, 35, 1, 35, 5, 35, 1124, 8, 35, 10, 35, 12, 35, 1127, 9, 35, 1, 35,
1, 35, 3, 35, 1131, 8, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 1138,
8, 35, 10, 35, 12, 35, 1141, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35,
1, 35, 5, 35, 1149, 8, 35, 10, 35, 12, 35, 1152, 9, 35, 1, 35, 1, 35, 5,
35, 1156, 8, 35, 10, 35, 12, 35, 1159, 9, 35, 1, 35, 3, 35, 1162, 8, 35,
1, 35, 3, 35, 1165, 8, 35, 1, 35, 1, 35, 3, 35, 1169, 8, 35, 1, 35, 3,
35, 1172, 8, 35, 1, 36, 1, 36, 1, 36, 1, 36, 5, 36, 1178, 8, 36, 10, 36,
12, 36, 1181, 9, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 1189,
8, 37, 10, 37, 12, 37, 1192, 9, 37, 1, 37, 1, 37, 1, 37, 3, 37, 1197, 8,
37, 3, 37, 1199, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37,
1207, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 1214, 8, 37, 1,
37, 1, 37, 1, 37, 5, 37, 1219, 8, 37, 10, 37, 12, 37, 1222, 9, 37, 1, 37,
1, 37, 3, 37, 1226, 8, 37, 3, 37, 1228, 8, 37, 1, 38, 1, 38, 1, 38, 1,
38, 3, 38, 1234, 8, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38,
3, 38, 1243, 8, 38, 1, 39, 1, 39, 1, 39, 3, 39, 1248, 8, 39, 1, 40, 1,
40, 1, 40, 1, 40, 1, 40, 3, 40, 1255, 8, 40, 1, 40, 1, 40, 3, 40, 1259,
8, 40, 3, 40, 1261, 8, 40, 1, 41, 3, 41, 1264, 8, 41, 1, 41, 1, 41, 1,
41, 1, 41, 5, 41, 1270, 8, 41, 10, 41, 12, 41, 1273, 9, 41, 1, 41, 3, 41,
1276, 8, 41, 1, 41, 3, 41, 1279, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 3,
42, 1285, 8, 42, 5, 42, 1287, 8, 42, 10, 42, 12, 42, 1290, 9, 42, 1, 43,
1, 43, 3, 43, 1294, 8, 43, 1, 43, 1, 43, 1, 43, 5, 43, 1299, 8, 43, 10,
43, 12, 43, 1302, 9, 43, 1, 43, 1, 43, 1, 43, 1, 43, 5, 43, 1308, 8, 43,
10, 43, 12, 43, 1311, 9, 43, 1, 43, 3, 43, 1314, 8, 43, 3, 43, 1316, 8,
43, 1, 43, 1, 43, 3, 43, 1320, 8, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43,
5, 43, 1327, 8, 43, 10, 43, 12, 43, 1330, 9, 43, 1, 43, 1, 43, 3, 43, 1334,
8, 43, 3, 43, 1336, 8, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1,
43, 1, 43, 1, 43, 5, 43, 1347, 8, 43, 10, 43, 12, 43, 1350, 9, 43, 3, 43,
1352, 8, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 5, 43, 1359, 8, 43, 10,
43, 12, 43, 1362, 9, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 5, 43,
1370, 8, 43, 10, 43, 12, 43, 1373, 9, 43, 1, 43, 1, 43, 5, 43, 1377, 8,
43, 10, 43, 12, 43, 1380, 9, 43, 3, 43, 1382, 8, 43, 1, 44, 1, 44, 1, 45,
3, 45, 1387, 8, 45, 1, 45, 1, 45, 3, 45, 1391, 8, 45, 1, 45, 3, 45, 1394,
8, 45, 1, 46, 3, 46, 1397, 8, 46, 1, 46, 1, 46, 1, 46, 3, 46, 1402, 8,
46, 1, 46, 1, 46, 3, 46, 1406, 8, 46, 1, 46, 4, 46, 1409, 8, 46, 11, 46,
12, 46, 1410, 1, 46, 3, 46, 1414, 8, 46, 1, 46, 3, 46, 1417, 8, 46, 1,
47, 1, 47, 1, 47, 3, 47, 1422, 8, 47, 1, 47, 1, 47, 3, 47, 1426, 8, 47,
1, 47, 3, 47, 1429, 8, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 1436,
8, 47, 1, 47, 1, 47, 1, 47, 3, 47, 1441, 8, 47, 1, 47, 1, 47, 1, 47, 1,
47, 1, 47, 5, 47, 1448, 8, 47, 10, 47, 12, 47, 1451, 9, 47, 1, 47, 1, 47,
3, 47, 1455, 8, 47, 1, 47, 3, 47, 1458, 8, 47, 1, 47, 1, 47, 1, 47, 1,
47, 5, 47, 1464, 8, 47, 10, 47, 12, 47, 1467, 9, 47, 1, 47, 3, 47, 1470,
8, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 1478, 8, 47, 1,
47, 3, 47, 1481, 8, 47, 3, 47, 1483, 8, 47, 1, 48, 1, 48, 1, 48, 1, 48,
1, 48, 1, 48, 1, 48, 3, 48, 1492, 8, 48, 1, 48, 3, 48, 1495, 8, 48, 3,
48, 1497, 8, 48, 1, 49, 1, 49, 3, 49, 1501, 8, 49, 1, 49, 1, 49, 3, 49,
1505, 8, 49, 1, 49, 1, 49, 3, 49, 1509, 8, 49, 1, 49, 3, 49, 1512, 8, 49,
1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 5, 50, 1521, 8, 50, 10,
50, 12, 50, 1524, 9, 50, 1, 50, 1, 50, 3, 50, 1528, 8, 50, 1, 51, 1, 51,
3, 51, 1532, 8, 51, 1, 51, 1, 51, 3, 51, 1536, 8, 51, 1, 52, 3, 52, 1539,
8, 52, 1, 52, 1, 52, 1, 52, 3, 52, 1544, 8, 52, 1, 52, 1, 52, 1, 52, 1,
52, 1, 52, 1, 52, 1, 52, 5, 52, 1553, 8, 52, 10, 52, 12, 52, 1556, 9, 52,
1, 52, 3, 52, 1559, 8, 52, 3, 52, 1561, 8, 52, 1, 52, 1, 52, 3, 52, 1565,
8, 52, 1, 52, 3, 52, 1568, 8, 52, 1, 53, 1, 53, 1, 53, 5, 53, 1573, 8,
53, 10, 53, 12, 53, 1576, 9, 53, 1, 54, 1, 54, 3, 54, 1580, 8, 54, 1, 54,
1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 5, 55, 1589, 8, 55, 10, 55, 12,
55, 1592, 9, 55, 1, 55, 1, 55, 1, 56, 3, 56, 1597, 8, 56, 1, 56, 1, 56,
1, 56, 3, 56, 1602, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 3, 56, 1608, 8,
56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 3, 56, 1615, 8, 56, 1, 56, 1, 56,
1, 56, 5, 56, 1620, 8, 56, 10, 56, 12, 56, 1623, 9, 56, 1, 56, 1, 56, 3,
56, 1627, 8, 56, 1, 56, 3, 56, 1630, 8, 56, 1, 56, 3, 56, 1633, 8, 56,
1, 56, 3, 56, 1636, 8, 56, 1, 57, 1, 57, 1, 57, 3, 57, 1641, 8, 57, 1,
57, 1, 57, 1, 57, 3, 57, 1646, 8, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57,
3, 57, 1653, 8, 57, 1, 58, 1, 58, 3, 58, 1657, 8, 58, 1, 58, 1, 58, 3,
58, 1661, 8, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60,
3, 60, 1671, 8, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 5, 60, 1678, 8,
60, 10, 60, 12, 60, 1681, 9, 60, 3, 60, 1683, 8, 60, 1, 60, 1, 60, 1, 60,
1, 60, 1, 60, 5, 60, 1690, 8, 60, 10, 60, 12, 60, 1693, 9, 60, 1, 60, 3,
60, 1696, 8, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 3, 61, 1704,
8, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 5, 61, 1711, 8, 61, 10, 61, 12,
61, 1714, 9, 61, 3, 61, 1716, 8, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61,
5, 61, 1723, 8, 61, 10, 61, 12, 61, 1726, 9, 61, 3, 61, 1728, 8, 61, 1,
61, 3, 61, 1731, 8, 61, 1, 61, 3, 61, 1734, 8, 61, 1, 62, 1, 62, 1, 62,
1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 1744, 8, 62, 1, 63, 1, 63, 1,
63, 1, 63, 1, 63, 1, 63, 1, 63, 3, 63, 1753, 8, 63, 1, 64, 1, 64, 1, 64,
1, 64, 1, 64, 5, 64, 1760, 8, 64, 10, 64, 12, 64, 1763, 9, 64, 1, 64, 3,
64, 1766, 8, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 3, 65, 1773, 8, 65,
1, 65, 1, 65, 1, 65, 5, 65, 1778, 8, 65, 10, 65, 12, 65, 1781, 9, 65, 1,
65, 3, 65, 1784, 8, 65, 1, 65, 1, 65, 3, 65, 1788, 8, 65, 1, 66, 1, 66,
1, 66, 1, 66, 1, 66, 5, 66, 1795, 8, 66, 10, 66, 12, 66, 1798, 9, 66, 1,
66, 3, 66, 1801, 8, 66, 1, 66, 1, 66, 3, 66, 1805, 8, 66, 1, 66, 1, 66,
1, 66, 3, 66, 1810, 8, 66, 1, 67, 1, 67, 3, 67, 1814, 8, 67, 1, 67, 1,
67, 1, 67, 5, 67, 1819, 8, 67, 10, 67, 12, 67, 1822, 9, 67, 1, 68, 1, 68,
1, 68, 1, 68, 1, 68, 5, 68, 1829, 8, 68, 10, 68, 12, 68, 1832, 9, 68, 1,
69, 1, 69, 1, 69, 1, 69, 3, 69, 1838, 8, 69, 1, 70, 1, 70, 1, 70, 3, 70,
1843, 8, 70, 1, 70, 3, 70, 1846, 8, 70, 1, 70, 1, 70, 3, 70, 1850, 8, 70,
1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1,
72, 1, 72, 3, 72, 1864, 8, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73,
1, 73, 1, 73, 1, 73, 1, 73, 3, 73, 1876, 8, 73, 1, 74, 1, 74, 1, 74, 1,
74, 1, 74, 1, 74, 1, 74, 3, 74, 1885, 8, 74, 1, 75, 1, 75, 1, 75, 1, 75,
1, 75, 1, 75, 1, 75, 3, 75, 1894, 8, 75, 1, 75, 1, 75, 3, 75, 1898, 8,
75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 3, 75, 1908,
8, 75, 1, 75, 3, 75, 1911, 8, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1,
75, 1, 75, 3, 75, 1920, 8, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75,
1, 75, 3, 75, 1929, 8, 75, 1, 75, 3, 75, 1932, 8, 75, 1, 75, 1, 75, 1,
75, 1, 75, 3, 75, 1938, 8, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75,
1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 3, 75, 1952, 8, 75, 1, 75, 1,
75, 3, 75, 1956, 8, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75,
1, 75, 1, 75, 3, 75, 1967, 8, 75, 1, 75, 1, 75, 1, 75, 3, 75, 1972, 8,
75, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 4, 78,
1983, 8, 78, 11, 78, 12, 78, 1984, 1, 79, 1, 79, 1, 79, 4, 79, 1990, 8,
79, 11, 79, 12, 79, 1991, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 3,
81, 2000, 8, 81, 1, 81, 1, 81, 1, 81, 3, 81, 2005, 8, 81, 5, 81, 2007,
8, 81, 10, 81, 12, 81, 2010, 9, 81, 1, 82, 1, 82, 1, 83, 1, 83, 1, 84,
1, 84, 1, 85, 1, 85, 1, 86, 1, 86, 3, 86, 2022, 8, 86, 1, 87, 1, 87, 1,
88, 1, 88, 1, 89, 1, 89, 1, 90, 1, 90, 1, 91, 1, 91, 1, 92, 1, 92, 1, 93,
1, 93, 1, 94, 1, 94, 1, 95, 1, 95, 1, 96, 1, 96, 1, 97, 1, 97, 1, 98, 1,
98, 1, 99, 1, 99, 1, 100, 1, 100, 1, 101, 1, 101, 1, 102, 1, 102, 1, 103,
1, 103, 1, 104, 1, 104, 1, 105, 1, 105, 1, 106, 1, 106, 1, 107, 1, 107,
1, 108, 1, 108, 1, 109, 1, 109, 1, 110, 1, 110, 1, 111, 1, 111, 1, 112,
1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 3, 112, 2081, 8, 112, 1,
112, 2, 440, 472, 1, 64, 113, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22,
24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58,
60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94,
96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124,
126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154,
156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184,
186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214,
216, 218, 220, 222, 224, 0, 28, 3, 0, 58, 58, 69, 69, 82, 82, 2, 0, 47,
47, 66, 66, 1, 0, 133, 134, 2, 0, 146, 146, 171, 171, 1, 0, 8, 9, 2, 0,
59, 59, 141, 141, 2, 0, 56, 56, 104, 104, 2, 0, 58, 58, 82, 82, 5, 0, 25,
25, 72, 72, 81, 81, 122, 122, 126, 126, 4, 0, 84, 84, 132, 132, 138, 138,
145, 145, 2, 0, 7, 7, 12, 13, 1, 0, 14, 17, 1, 0, 18, 21, 4, 0, 77, 77,
97, 97, 99, 99, 118, 118, 3, 0, 25, 25, 72, 72, 126, 126, 5, 0, 52, 54,
104, 104, 172, 173, 186, 186, 188, 189, 2, 0, 29, 29, 62, 62, 3, 0, 128,
128, 154, 154, 179, 179, 2, 0, 5, 5, 106, 106, 1, 0, 176, 177, 2, 0, 34,
34, 60, 60, 2, 0, 151, 151, 162, 162, 2, 0, 159, 159, 166, 166, 2, 0, 160,
160, 167, 168, 2, 0, 161, 161, 163, 163, 2, 0, 8, 10, 102, 102, 2, 0, 185,
185, 188, 188, 2, 0, 25, 123, 125, 180, 2367, 0, 229, 1, 0, 0, 0, 2, 237,
1, 0, 0, 0, 4, 263, 1, 0, 0, 0, 6, 291, 1, 0, 0, 0, 8, 323, 1, 0, 0, 0,
10, 333, 1, 0, 0, 0, 12, 341, 1, 0, 0, 0, 14, 351, 1, 0, 0, 0, 16, 355,
1, 0, 0, 0, 18, 366, 1, 0, 0, 0, 20, 369, 1, 0, 0, 0, 22, 375, 1, 0, 0,
0, 24, 409, 1, 0, 0, 0, 26, 418, 1, 0, 0, 0, 28, 459, 1, 0, 0, 0, 30, 470,
1, 0, 0, 0, 32, 488, 1, 0, 0, 0, 34, 540, 1, 0, 0, 0, 36, 546, 1, 0, 0,
0, 38, 587, 1, 0, 0, 0, 40, 629, 1, 0, 0, 0, 42, 633, 1, 0, 0, 0, 44, 697,
1, 0, 0, 0, 46, 729, 1, 0, 0, 0, 48, 758, 1, 0, 0, 0, 50, 779, 1, 0, 0,
0, 52, 793, 1, 0, 0, 0, 54, 804, 1, 0, 0, 0, 56, 824, 1, 0, 0, 0, 58, 837,
1, 0, 0, 0, 60, 855, 1, 0, 0, 0, 62, 861, 1, 0, 0, 0, 64, 962, 1, 0, 0,
0, 66, 1086, 1, 0, 0, 0, 68, 1096, 1, 0, 0, 0, 70, 1099, 1, 0, 0, 0, 72,
1173, 1, 0, 0, 0, 74, 1182, 1, 0, 0, 0, 76, 1229, 1, 0, 0, 0, 78, 1247,
1, 0, 0, 0, 80, 1249, 1, 0, 0, 0, 82, 1263, 1, 0, 0, 0, 84, 1280, 1, 0,
0, 0, 86, 1381, 1, 0, 0, 0, 88, 1383, 1, 0, 0, 0, 90, 1386, 1, 0, 0, 0,
92, 1396, 1, 0, 0, 0, 94, 1482, 1, 0, 0, 0, 96, 1496, 1, 0, 0, 0, 98, 1511,
1, 0, 0, 0, 100, 1527, 1, 0, 0, 0, 102, 1535, 1, 0, 0, 0, 104, 1538, 1,
0, 0, 0, 106, 1569, 1, 0, 0, 0, 108, 1579, 1, 0, 0, 0, 110, 1584, 1, 0,
0, 0, 112, 1596, 1, 0, 0, 0, 114, 1640, 1, 0, 0, 0, 116, 1654, 1, 0, 0,
0, 118, 1662, 1, 0, 0, 0, 120, 1668, 1, 0, 0, 0, 122, 1699, 1, 0, 0, 0,
124, 1735, 1, 0, 0, 0, 126, 1745, 1, 0, 0, 0, 128, 1754, 1, 0, 0, 0, 130,
1769, 1, 0, 0, 0, 132, 1789, 1, 0, 0, 0, 134, 1811, 1, 0, 0, 0, 136, 1823,
1, 0, 0, 0, 138, 1833, 1, 0, 0, 0, 140, 1839, 1, 0, 0, 0, 142, 1851, 1,
0, 0, 0, 144, 1863, 1, 0, 0, 0, 146, 1875, 1, 0, 0, 0, 148, 1884, 1, 0,
0, 0, 150, 1971, 1, 0, 0, 0, 152, 1973, 1, 0, 0, 0, 154, 1976, 1, 0, 0,
0, 156, 1979, 1, 0, 0, 0, 158, 1986, 1, 0, 0, 0, 160, 1993, 1, 0, 0, 0,
162, 1997, 1, 0, 0, 0, 164, 2011, 1, 0, 0, 0, 166, 2013, 1, 0, 0, 0, 168,
2015, 1, 0, 0, 0, 170, 2017, 1, 0, 0, 0, 172, 2021, 1, 0, 0, 0, 174, 2023,
1, 0, 0, 0, 176, 2025, 1, 0, 0, 0, 178, 2027, 1, 0, 0, 0, 180, 2029, 1,
0, 0, 0, 182, 2031, 1, 0, 0, 0, 184, 2033, 1, 0, 0, 0, 186, 2035, 1, 0,
0, 0, 188, 2037, 1, 0, 0, 0, 190, 2039, 1, 0, 0, 0, 192, 2041, 1, 0, 0,
0, 194, 2043, 1, 0, 0, 0, 196, 2045, 1, 0, 0, 0, 198, 2047, 1, 0, 0, 0,
200, 2049, 1, 0, 0, 0, 202, 2051, 1, 0, 0, 0, 204, 2053, 1, 0, 0, 0, 206,
2055, 1, 0, 0, 0, 208, 2057, 1, 0, 0, 0, 210, 2059, 1, 0, 0, 0, 212, 2061,
1, 0, 0, 0, 214, 2063, 1, 0, 0, 0, 216, 2065, 1, 0, 0, 0, 218, 2067, 1,
0, 0, 0, 220, 2069, 1, 0, 0, 0, 222, 2071, 1, 0, 0, 0, 224, 2080, 1, 0,
0, 0, 226, 228, 3, 2, 1, 0, 227, 226, 1, 0, 0, 0, 228, 231, 1, 0, 0, 0,
229, 227, 1, 0, 0, 0, 229, 230, 1, 0, 0, 0, 230, 232, 1, 0, 0, 0, 231,
229, 1, 0, 0, 0, 232, 233, 5, 0, 0, 1, 233, 1, 1, 0, 0, 0, 234, 236, 5,
1, 0, 0, 235, 234, 1, 0, 0, 0, 236, 239, 1, 0, 0, 0, 237, 235, 1, 0, 0,
0, 237, 238, 1, 0, 0, 0, 238, 240, 1, 0, 0, 0, 239, 237, 1, 0, 0, 0, 240,
249, 3, 4, 2, 0, 241, 243, 5, 1, 0, 0, 242, 241, 1, 0, 0, 0, 243, 244,
1, 0, 0, 0, 244, 242, 1, 0, 0, 0, 244, 245, 1, 0, 0, 0, 245, 246, 1, 0,
0, 0, 246, 248, 3, 4, 2, 0, 247, 242, 1, 0, 0, 0, 248, 251, 1, 0, 0, 0,
249, 247, 1, 0, 0, 0, 249, 250, 1, 0, 0, 0, 250, 255, 1, 0, 0, 0, 251,
249, 1, 0, 0, 0, 252, 254, 5, 1, 0, 0, 253, 252, 1, 0, 0, 0, 254, 257,
1, 0, 0, 0, 255, 253, 1, 0, 0, 0, 255, 256, 1, 0, 0, 0, 256, 3, 1, 0, 0,
0, 257, 255, 1, 0, 0, 0, 258, 261, 5, 71, 0, 0, 259, 260, 5, 114, 0, 0,
260, 262, 5, 111, 0, 0, 261, 259, 1, 0, 0, 0, 261, 262, 1, 0, 0, 0, 262,
264, 1, 0, 0, 0, 263, 258, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 289,
1, 0, 0, 0, 265, 290, 3, 6, 3, 0, 266, 290, 3, 8, 4, 0, 267, 290, 3, 10,
5, 0, 268, 290, 3, 12, 6, 0, 269, 290, 3, 14, 7, 0, 270, 290, 3, 22, 11,
0, 271, 290, 3, 26, 13, 0, 272, 290, 3, 42, 21, 0, 273, 290, 3, 44, 22,
0, 274, 290, 3, 46, 23, 0, 275, 290, 3, 56, 28, 0, 276, 290, 3, 58, 29,
0, 277, 290, 3, 60, 30, 0, 278, 290, 3, 62, 31, 0, 279, 290, 3, 70, 35,
0, 280, 290, 3, 76, 38, 0, 281, 290, 3, 80, 40, 0, 282, 290, 3, 20, 10,
0, 283, 290, 3, 16, 8, 0, 284, 290, 3, 18, 9, 0, 285, 290, 3, 82, 41, 0,
286, 290, 3, 104, 52, 0, 287, 290, 3, 112, 56, 0, 288, 290, 3, 116, 58,
0, 289, 265, 1, 0, 0, 0, 289, 266, 1, 0, 0, 0, 289, 267, 1, 0, 0, 0, 289,
268, 1, 0, 0, 0, 289, 269, 1, 0, 0, 0, 289, 270, 1, 0, 0, 0, 289, 271,
1, 0, 0, 0, 289, 272, 1, 0, 0, 0, 289, 273, 1, 0, 0, 0, 289, 274, 1, 0,
0, 0, 289, 275, 1, 0, 0, 0, 289, 276, 1, 0, 0, 0, 289, 277, 1, 0, 0, 0,
289, 278, 1, 0, 0, 0, 289, 279, 1, 0, 0, 0, 289, 280, 1, 0, 0, 0, 289,
281, 1, 0, 0, 0, 289, 282, 1, 0, 0, 0, 289, 283, 1, 0, 0, 0, 289, 284,
1, 0, 0, 0, 289, 285, 1, 0, 0, 0, 289, 286, 1, 0, 0, 0, 289, 287, 1, 0,
0, 0, 289, 288, 1, 0, 0, 0, 290, 5, 1, 0, 0, 0, 291, 292, 5, 30, 0, 0,
292, 296, 5, 132, 0, 0, 293, 294, 3, 182, 91, 0, 294, 295, 5, 2, 0, 0,
295, 297, 1, 0, 0, 0, 296, 293, 1, 0, 0, 0, 296, 297, 1, 0, 0, 0, 297,
298, 1, 0, 0, 0, 298, 321, 3, 184, 92, 0, 299, 309, 5, 121, 0, 0, 300,
301, 5, 136, 0, 0, 301, 310, 3, 184, 92, 0, 302, 304, 5, 46, 0, 0, 303,
302, 1, 0, 0, 0, 303, 304, 1, 0, 0, 0, 304, 305, 1, 0, 0, 0, 305, 306,
3, 188, 94, 0, 306, 307, 5, 136, 0, 0, 307, 308, 3, 188, 94, 0, 308, 310,
1, 0, 0, 0, 309, 300, 1, 0, 0, 0, 309, 303, 1, 0, 0, 0, 310, 322, 1, 0,
0, 0, 311, 313, 5, 27, 0, 0, 312, 314, 5, 46, 0, 0, 313, 312, 1, 0, 0,
0, 313, 314, 1, 0, 0, 0, 314, 315, 1, 0, 0, 0, 315, 322, 3, 28, 14, 0,
316, 318, 5, 63, 0, 0, 317, 319, 5, 46, 0, 0, 318, 317, 1, 0, 0, 0, 318,
319, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 322, 3, 188, 94, 0, 321, 299,
1, 0, 0, 0, 321, 311, 1, 0, 0, 0, 321, 316, 1, 0, 0, 0, 322, 7, 1, 0, 0,
0, 323, 331, 5, 31, 0, 0, 324, 332, 3, 182, 91, 0, 325, 326, 3, 182, 91,
0, 326, 327, 5, 2, 0, 0, 327, 329, 1, 0, 0, 0, 328, 325, 1, 0, 0, 0, 328,
329, 1, 0, 0, 0, 329, 330, 1, 0, 0, 0, 330, 332, 3, 186, 93, 0, 331, 324,
1, 0, 0, 0, 331, 328, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 9, 1, 0, 0,
0, 333, 335, 5, 35, 0, 0, 334, 336, 5, 55, 0, 0, 335, 334, 1, 0, 0, 0,
335, 336, 1, 0, 0, 0, 336, 337, 1, 0, 0, 0, 337, 338, 3, 64, 32, 0, 338,
339, 5, 33, 0, 0, 339, 340, 3, 182, 91, 0, 340, 11, 1, 0, 0, 0, 341, 343,
5, 38, 0, 0, 342, 344, 7, 0, 0, 0, 343, 342, 1, 0, 0, 0, 343, 344, 1, 0,
0, 0, 344, 349, 1, 0, 0, 0, 345, 347, 5, 137, 0, 0, 346, 348, 3, 208, 104,
0, 347, 346, 1, 0, 0, 0, 347, 348, 1, 0, 0, 0, 348, 350, 1, 0, 0, 0, 349,
345, 1, 0, 0, 0, 349, 350, 1, 0, 0, 0, 350, 13, 1, 0, 0, 0, 351, 353, 7,
1, 0, 0, 352, 354, 5, 137, 0, 0, 353, 352, 1, 0, 0, 0, 353, 354, 1, 0,
0, 0, 354, 15, 1, 0, 0, 0, 355, 357, 5, 126, 0, 0, 356, 358, 5, 137, 0,
0, 357, 356, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 364, 1, 0, 0, 0, 359,
361, 5, 136, 0, 0, 360, 362, 5, 129, 0, 0, 361, 360, 1, 0, 0, 0, 361, 362,
1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 365, 3, 204, 102, 0, 364, 359, 1,
0, 0, 0, 364, 365, 1, 0, 0, 0, 365, 17, 1, 0, 0, 0, 366, 367, 5, 129, 0,
0, 367, 368, 3, 204, 102, 0, 368, 19, 1, 0, 0, 0, 369, 371, 5, 120, 0,
0, 370, 372, 5, 129, 0, 0, 371, 370, 1, 0, 0, 0, 371, 372, 1, 0, 0, 0,
372, 373, 1, 0, 0, 0, 373, 374, 3, 204, 102, 0, 374, 21, 1, 0, 0, 0, 375,
377, 5, 50, 0, 0, 376, 378, 5, 140, 0, 0, 377, 376, 1, 0, 0, 0, 377, 378,
1, 0, 0, 0, 378, 379, 1, 0, 0, 0, 379, 383, 5, 84, 0, 0, 380, 381, 5, 80,
0, 0, 381, 382, 5, 102, 0, 0, 382, 384, 5, 70, 0, 0, 383, 380, 1, 0, 0,
0, 383, 384, 1, 0, 0, 0, 384, 388, 1, 0, 0, 0, 385, 386, 3, 182, 91, 0,
386, 387, 5, 2, 0, 0, 387, 389, 1, 0, 0, 0, 388, 385, 1, 0, 0, 0, 388,
389, 1, 0, 0, 0, 389, 390, 1, 0, 0, 0, 390, 391, 3, 194, 97, 0, 391, 392,
5, 107, 0, 0, 392, 393, 3, 184, 92, 0, 393, 394, 5, 3, 0, 0, 394, 399,
3, 24, 12, 0, 395, 396, 5, 5, 0, 0, 396, 398, 3, 24, 12, 0, 397, 395, 1,
0, 0, 0, 398, 401, 1, 0, 0, 0, 399, 397, 1, 0, 0, 0, 399, 400, 1, 0, 0,
0, 400, 402, 1, 0, 0, 0, 401, 399, 1, 0, 0, 0, 402, 405, 5, 4, 0, 0, 403,
404, 5, 148, 0, 0, 404, 406, 3, 64, 32, 0, 405, 403, 1, 0, 0, 0, 405, 406,
1, 0, 0, 0, 406, 23, 1, 0, 0, 0, 407, 410, 3, 188, 94, 0, 408, 410, 3,
64, 32, 0, 409, 407, 1, 0, 0, 0, 409, 408, 1, 0, 0, 0, 410, 413, 1, 0,
0, 0, 411, 412, 5, 45, 0, 0, 412, 414, 3, 190, 95, 0, 413, 411, 1, 0, 0,
0, 413, 414, 1, 0, 0, 0, 414, 416, 1, 0, 0, 0, 415, 417, 3, 142, 71, 0,
416, 415, 1, 0, 0, 0, 416, 417, 1, 0, 0, 0, 417, 25, 1, 0, 0, 0, 418, 420,
5, 50, 0, 0, 419, 421, 7, 2, 0, 0, 420, 419, 1, 0, 0, 0, 420, 421, 1, 0,
0, 0, 421, 422, 1, 0, 0, 0, 422, 426, 5, 132, 0, 0, 423, 424, 5, 80, 0,
0, 424, 425, 5, 102, 0, 0, 425, 427, 5, 70, 0, 0, 426, 423, 1, 0, 0, 0,
426, 427, 1, 0, 0, 0, 427, 431, 1, 0, 0, 0, 428, 429, 3, 182, 91, 0, 429,
430, 5, 2, 0, 0, 430, 432, 1, 0, 0, 0, 431, 428, 1, 0, 0, 0, 431, 432,
1, 0, 0, 0, 432, 433, 1, 0, 0, 0, 433, 457, 3, 184, 92, 0, 434, 435, 5,
3, 0, 0, 435, 440, 3, 28, 14, 0, 436, 437, 5, 5, 0, 0, 437, 439, 3, 28,
14, 0, 438, 436, 1, 0, 0, 0, 439, 442, 1, 0, 0, 0, 440, 441, 1, 0, 0, 0,
440, 438, 1, 0, 0, 0, 441, 447, 1, 0, 0, 0, 442, 440, 1, 0, 0, 0, 443,
444, 5, 5, 0, 0, 444, 446, 3, 36, 18, 0, 445, 443, 1, 0, 0, 0, 446, 449,
1, 0, 0, 0, 447, 445, 1, 0, 0, 0, 447, 448, 1, 0, 0, 0, 448, 450, 1, 0,
0, 0, 449, 447, 1, 0, 0, 0, 450, 453, 5, 4, 0, 0, 451, 452, 5, 150, 0,
0, 452, 454, 5, 185, 0, 0, 453, 451, 1, 0, 0, 0, 453, 454, 1, 0, 0, 0,
454, 458, 1, 0, 0, 0, 455, 456, 5, 33, 0, 0, 456, 458, 3, 82, 41, 0, 457,
434, 1, 0, 0, 0, 457, 455, 1, 0, 0, 0, 458, 27, 1, 0, 0, 0, 459, 461, 3,
188, 94, 0, 460, 462, 3, 30, 15, 0, 461, 460, 1, 0, 0, 0, 461, 462, 1,
0, 0, 0, 462, 466, 1, 0, 0, 0, 463, 465, 3, 32, 16, 0, 464, 463, 1, 0,
0, 0, 465, 468, 1, 0, 0, 0, 466, 464, 1, 0, 0, 0, 466, 467, 1, 0, 0, 0,
467, 29, 1, 0, 0, 0, 468, 466, 1, 0, 0, 0, 469, 471, 3, 178, 89, 0, 470,
469, 1, 0, 0, 0, 471, 472, 1, 0, 0, 0, 472, 473, 1, 0, 0, 0, 472, 470,
1, 0, 0, 0, 473, 484, 1, 0, 0, 0, 474, 475, 5, 3, 0, 0, 475, 476, 3, 34,
17, 0, 476, 477, 5, 4, 0, 0, 477, 485, 1, 0, 0, 0, 478, 479, 5, 3, 0, 0,
479, 480, 3, 34, 17, 0, 480, 481, 5, 5, 0, 0, 481, 482, 3, 34, 17, 0, 482,
483, 5, 4, 0, 0, 483, 485, 1, 0, 0, 0, 484, 474, 1, 0, 0, 0, 484, 478,
1, 0, 0, 0, 484, 485, 1, 0, 0, 0, 485, 31, 1, 0, 0, 0, 486, 487, 5, 49,
0, 0, 487, 489, 3, 178, 89, 0, 488, 486, 1, 0, 0, 0, 488, 489, 1, 0, 0,
0, 489, 537, 1, 0, 0, 0, 490, 491, 5, 113, 0, 0, 491, 493, 5, 95, 0, 0,
492, 494, 3, 142, 71, 0, 493, 492, 1, 0, 0, 0, 493, 494, 1, 0, 0, 0, 494,
496, 1, 0, 0, 0, 495, 497, 3, 40, 20, 0, 496, 495, 1, 0, 0, 0, 496, 497,
1, 0, 0, 0, 497, 499, 1, 0, 0, 0, 498, 500, 5, 36, 0, 0, 499, 498, 1, 0,
0, 0, 499, 500, 1, 0, 0, 0, 500, 538, 1, 0, 0, 0, 501, 502, 5, 102, 0,
0, 502, 505, 5, 104, 0, 0, 503, 505, 5, 140, 0, 0, 504, 501, 1, 0, 0, 0,
504, 503, 1, 0, 0, 0, 505, 507, 1, 0, 0, 0, 506, 508, 3, 40, 20, 0, 507,
506, 1, 0, 0, 0, 507, 508, 1, 0, 0, 0, 508, 538, 1, 0, 0, 0, 509, 510,
5, 44, 0, 0, 510, 511, 5, 3, 0, 0, 511, 512, 3, 64, 32, 0, 512, 513, 5,
4, 0, 0, 513, 538, 1, 0, 0, 0, 514, 521, 5, 56, 0, 0, 515, 522, 3, 34,
17, 0, 516, 522, 3, 68, 34, 0, 517, 518, 5, 3, 0, 0, 518, 519, 3, 64, 32,
0, 519, 520, 5, 4, 0, 0, 520, 522, 1, 0, 0, 0, 521, 515, 1, 0, 0, 0, 521,
516, 1, 0, 0, 0, 521, 517, 1, 0, 0, 0, 522, 538, 1, 0, 0, 0, 523, 524,
5, 45, 0, 0, 524, 538, 3, 190, 95, 0, 525, 538, 3, 38, 19, 0, 526, 527,
5, 169, 0, 0, 527, 529, 5, 170, 0, 0, 528, 526, 1, 0, 0, 0, 528, 529, 1,
0, 0, 0, 529, 530, 1, 0, 0, 0, 530, 531, 5, 33, 0, 0, 531, 532, 5, 3, 0,
0, 532, 533, 3, 64, 32, 0, 533, 535, 5, 4, 0, 0, 534, 536, 7, 3, 0, 0,
535, 534, 1, 0, 0, 0, 535, 536, 1, 0, 0, 0, 536, 538, 1, 0, 0, 0, 537,
490, 1, 0, 0, 0, 537, 504, 1, 0, 0, 0, 537, 509, 1, 0, 0, 0, 537, 514,
1, 0, 0, 0, 537, 523, 1, 0, 0, 0, 537, 525, 1, 0, 0, 0, 537, 528, 1, 0,
0, 0, 538, 33, 1, 0, 0, 0, 539, 541, 7, 4, 0, 0, 540, 539, 1, 0, 0, 0,
540, 541, 1, 0, 0, 0, 541, 542, 1, 0, 0, 0, 542, 543, 5, 186, 0, 0, 543,
35, 1, 0, 0, 0, 544, 545, 5, 49, 0, 0, 545, 547, 3, 178, 89, 0, 546, 544,
1, 0, 0, 0, 546, 547, 1, 0, 0, 0, 547, 585, 1, 0, 0, 0, 548, 549, 5, 113,
0, 0, 549, 552, 5, 95, 0, 0, 550, 552, 5, 140, 0, 0, 551, 548, 1, 0, 0,
0, 551, 550, 1, 0, 0, 0, 552, 553, 1, 0, 0, 0, 553, 554, 5, 3, 0, 0, 554,
559, 3, 24, 12, 0, 555, 556, 5, 5, 0, 0, 556, 558, 3, 24, 12, 0, 557, 555,
1, 0, 0, 0, 558, 561, 1, 0, 0, 0, 559, 557, 1, 0, 0, 0, 559, 560, 1, 0,
0, 0, 560, 562, 1, 0, 0, 0, 561, 559, 1, 0, 0, 0, 562, 564, 5, 4, 0, 0,
563, 565, 3, 40, 20, 0, 564, 563, 1, 0, 0, 0, 564, 565, 1, 0, 0, 0, 565,
586, 1, 0, 0, 0, 566, 567, 5, 44, 0, 0, 567, 568, 5, 3, 0, 0, 568, 569,
3, 64, 32, 0, 569, 570, 5, 4, 0, 0, 570, 586, 1, 0, 0, 0, 571, 572, 5,
74, 0, 0, 572, 573, 5, 95, 0, 0, 573, 574, 5, 3, 0, 0, 574, 579, 3, 188,
94, 0, 575, 576, 5, 5, 0, 0, 576, 578, 3, 188, 94, 0, 577, 575, 1, 0, 0,
0, 578, 581, 1, 0, 0, 0, 579, 577, 1, 0, 0, 0, 579, 580, 1, 0, 0, 0, 580,
582, 1, 0, 0, 0, 581, 579, 1, 0, 0, 0, 582, 583, 5, 4, 0, 0, 583, 584,
3, 38, 19, 0, 584, 586, 1, 0, 0, 0, 585, 551, 1, 0, 0, 0, 585, 566, 1,
0, 0, 0, 585, 571, 1, 0, 0, 0, 586, 37, 1, 0, 0, 0, 587, 588, 5, 117, 0,
0, 588, 600, 3, 192, 96, 0, 589, 590, 5, 3, 0, 0, 590, 595, 3, 188, 94,
0, 591, 592, 5, 5, 0, 0, 592, 594, 3, 188, 94, 0, 593, 591, 1, 0, 0, 0,
594, 597, 1, 0, 0, 0, 595, 593, 1, 0, 0, 0, 595, 596, 1, 0, 0, 0, 596,
598, 1, 0, 0, 0, 597, 595, 1, 0, 0, 0, 598, 599, 5, 4, 0, 0, 599, 601,
1, 0, 0, 0, 600, 589, 1, 0, 0, 0, 600, 601, 1, 0, 0, 0, 601, 616, 1, 0,
0, 0, 602, 603, 5, 107, 0, 0, 603, 610, 7, 5, 0, 0, 604, 605, 5, 131, 0,
0, 605, 611, 7, 6, 0, 0, 606, 611, 5, 41, 0, 0, 607, 611, 5, 123, 0, 0,
608, 609, 5, 101, 0, 0, 609, 611, 5, 26, 0, 0, 610, 604, 1, 0, 0, 0, 610,
606, 1, 0, 0, 0, 610, 607, 1, 0, 0, 0, 610, 608, 1, 0, 0, 0, 611, 615,
1, 0, 0, 0, 612, 613, 5, 99, 0, 0, 613, 615, 3, 178, 89, 0, 614, 602, 1,
0, 0, 0, 614, 612, 1, 0, 0, 0, 615, 618, 1, 0, 0, 0, 616, 614, 1, 0, 0,
0, 616, 617, 1, 0, 0, 0, 617, 627, 1, 0, 0, 0, 618, 616, 1, 0, 0, 0, 619,
621, 5, 102, 0, 0, 620, 619, 1, 0, 0, 0, 620, 621, 1, 0, 0, 0, 621, 622,
1, 0, 0, 0, 622, 625, 5, 57, 0, 0, 623, 624, 5, 86, 0, 0, 624, 626, 7,
7, 0, 0, 625, 623, 1, 0, 0, 0, 625, 626, 1, 0, 0, 0, 626, 628, 1, 0, 0,
0, 627, 620, 1, 0, 0, 0, 627, 628, 1, 0, 0, 0, 628, 39, 1, 0, 0, 0, 629,
630, 5, 107, 0, 0, 630, 631, 5, 48, 0, 0, 631, 632, 7, 8, 0, 0, 632, 41,
1, 0, 0, 0, 633, 635, 5, 50, 0, 0, 634, 636, 7, 2, 0, 0, 635, 634, 1, 0,
0, 0, 635, 636, 1, 0, 0, 0, 636, 637, 1, 0, 0, 0, 637, 641, 5, 138, 0,
0, 638, 639, 5, 80, 0, 0, 639, 640, 5, 102, 0, 0, 640, 642, 5, 70, 0, 0,
641, 638, 1, 0, 0, 0, 641, 642, 1, 0, 0, 0, 642, 646, 1, 0, 0, 0, 643,
644, 3, 182, 91, 0, 644, 645, 5, 2, 0, 0, 645, 647, 1, 0, 0, 0, 646, 643,
1, 0, 0, 0, 646, 647, 1, 0, 0, 0, 647, 648, 1, 0, 0, 0, 648, 653, 3, 196,
98, 0, 649, 654, 5, 37, 0, 0, 650, 654, 5, 28, 0, 0, 651, 652, 5, 89, 0,
0, 652, 654, 5, 105, 0, 0, 653, 649, 1, 0, 0, 0, 653, 650, 1, 0, 0, 0,
653, 651, 1, 0, 0, 0, 653, 654, 1, 0, 0, 0, 654, 669, 1, 0, 0, 0, 655,
670, 5, 59, 0, 0, 656, 670, 5, 88, 0, 0, 657, 667, 5, 141, 0, 0, 658, 659,
5, 105, 0, 0, 659, 664, 3, 188, 94, 0, 660, 661, 5, 5, 0, 0, 661, 663,
3, 188, 94, 0, 662, 660, 1, 0, 0, 0, 663, 666, 1, 0, 0, 0, 664, 662, 1,
0, 0, 0, 664, 665, 1, 0, 0, 0, 665, 668, 1, 0, 0, 0, 666, 664, 1, 0, 0,
0, 667, 658, 1, 0, 0, 0, 667, 668, 1, 0, 0, 0, 668, 670, 1, 0, 0, 0, 669,
655, 1, 0, 0, 0, 669, 656, 1, 0, 0, 0, 669, 657, 1, 0, 0, 0, 670, 671,
1, 0, 0, 0, 671, 672, 5, 107, 0, 0, 672, 676, 3, 184, 92, 0, 673, 674,
5, 73, 0, 0, 674, 675, 5, 64, 0, 0, 675, 677, 5, 127, 0, 0, 676, 673, 1,
0, 0, 0, 676, 677, 1, 0, 0, 0, 677, 680, 1, 0, 0, 0, 678, 679, 5, 147,
0, 0, 679, 681, 3, 64, 32, 0, 680, 678, 1, 0, 0, 0, 680, 681, 1, 0, 0,
0, 681, 682, 1, 0, 0, 0, 682, 691, 5, 38, 0, 0, 683, 688, 3, 104, 52, 0,
684, 688, 3, 70, 35, 0, 685, 688, 3, 56, 28, 0, 686, 688, 3, 82, 41, 0,
687, 683, 1, 0, 0, 0, 687, 684, 1, 0, 0, 0, 687, 685, 1, 0, 0, 0, 687,
686, 1, 0, 0, 0, 688, 689, 1, 0, 0, 0, 689, 690, 5, 1, 0, 0, 690, 692,
1, 0, 0, 0, 691, 687, 1, 0, 0, 0, 692, 693, 1, 0, 0, 0, 693, 691, 1, 0,
0, 0, 693, 694, 1, 0, 0, 0, 694, 695, 1, 0, 0, 0, 695, 696, 5, 66, 0, 0,
696, 43, 1, 0, 0, 0, 697, 699, 5, 50, 0, 0, 698, 700, 7, 2, 0, 0, 699,
698, 1, 0, 0, 0, 699, 700, 1, 0, 0, 0, 700, 701, 1, 0, 0, 0, 701, 705,
5, 145, 0, 0, 702, 703, 5, 80, 0, 0, 703, 704, 5, 102, 0, 0, 704, 706,
5, 70, 0, 0, 705, 702, 1, 0, 0, 0, 705, 706, 1, 0, 0, 0, 706, 710, 1, 0,
0, 0, 707, 708, 3, 182, 91, 0, 708, 709, 5, 2, 0, 0, 709, 711, 1, 0, 0,
0, 710, 707, 1, 0, 0, 0, 710, 711, 1, 0, 0, 0, 711, 712, 1, 0, 0, 0, 712,
724, 3, 198, 99, 0, 713, 714, 5, 3, 0, 0, 714, 719, 3, 188, 94, 0, 715,
716, 5, 5, 0, 0, 716, 718, 3, 188, 94, 0, 717, 715, 1, 0, 0, 0, 718, 721,
1, 0, 0, 0, 719, 717, 1, 0, 0, 0, 719, 720, 1, 0, 0, 0, 720, 722, 1, 0,
0, 0, 721, 719, 1, 0, 0, 0, 722, 723, 5, 4, 0, 0, 723, 725, 1, 0, 0, 0,
724, 713, 1, 0, 0, 0, 724, 725, 1, 0, 0, 0, 725, 726, 1, 0, 0, 0, 726,
727, 5, 33, 0, 0, 727, 728, 3, 82, 41, 0, 728, 45, 1, 0, 0, 0, 729, 730,
5, 50, 0, 0, 730, 731, 5, 146, 0, 0, 731, 735, 5, 132, 0, 0, 732, 733,
5, 80, 0, 0, 733, 734, 5, 102, 0, 0, 734, 736, 5, 70, 0, 0, 735, 732, 1,
0, 0, 0, 735, 736, 1, 0, 0, 0, 736, 740, 1, 0, 0, 0, 737, 738, 3, 182,
91, 0, 738, 739, 5, 2, 0, 0, 739, 741, 1, 0, 0, 0, 740, 737, 1, 0, 0, 0,
740, 741, 1, 0, 0, 0, 741, 742, 1, 0, 0, 0, 742, 743, 3, 184, 92, 0, 743,
744, 5, 142, 0, 0, 744, 756, 3, 200, 100, 0, 745, 746, 5, 3, 0, 0, 746,
751, 3, 172, 86, 0, 747, 748, 5, 5, 0, 0, 748, 750, 3, 172, 86, 0, 749,
747, 1, 0, 0, 0, 750, 753, 1, 0, 0, 0, 751, 749, 1, 0, 0, 0, 751, 752,
1, 0, 0, 0, 752, 754, 1, 0, 0, 0, 753, 751, 1, 0, 0, 0, 754, 755, 5, 4,
0, 0, 755, 757, 1, 0, 0, 0, 756, 745, 1, 0, 0, 0, 756, 757, 1, 0, 0, 0,
757, 47, 1, 0, 0, 0, 758, 760, 5, 149, 0, 0, 759, 761, 5, 116, 0, 0, 760,
759, 1, 0, 0, 0, 760, 761, 1, 0, 0, 0, 761, 762, 1, 0, 0, 0, 762, 763,
3, 50, 25, 0, 763, 764, 5, 33, 0, 0, 764, 765, 5, 3, 0, 0, 765, 766, 3,
82, 41, 0, 766, 776, 5, 4, 0, 0, 767, 768, 5, 5, 0, 0, 768, 769, 3, 50,
25, 0, 769, 770, 5, 33, 0, 0, 770, 771, 5, 3, 0, 0, 771, 772, 3, 82, 41,
0, 772, 773, 5, 4, 0, 0, 773, 775, 1, 0, 0, 0, 774, 767, 1, 0, 0, 0, 775,
778, 1, 0, 0, 0, 776, 774, 1, 0, 0, 0, 776, 777, 1, 0, 0, 0, 777, 49, 1,
0, 0, 0, 778, 776, 1, 0, 0, 0, 779, 791, 3, 184, 92, 0, 780, 781, 5, 3,
0, 0, 781, 786, 3, 188, 94, 0, 782, 783, 5, 5, 0, 0, 783, 785, 3, 188,
94, 0, 784, 782, 1, 0, 0, 0, 785, 788, 1, 0, 0, 0, 786, 784, 1, 0, 0, 0,
786, 787, 1, 0, 0, 0, 787, 789, 1, 0, 0, 0, 788, 786, 1, 0, 0, 0, 789,
790, 5, 4, 0, 0, 790, 792, 1, 0, 0, 0, 791, 780, 1, 0, 0, 0, 791, 792,
1, 0, 0, 0, 792, 51, 1, 0, 0, 0, 793, 794, 3, 50, 25, 0, 794, 795, 5, 33,
0, 0, 795, 796, 5, 3, 0, 0, 796, 797, 3, 164, 82, 0, 797, 799, 5, 139,
0, 0, 798, 800, 5, 29, 0, 0, 799, 798, 1, 0, 0, 0, 799, 800, 1, 0, 0, 0,
800, 801, 1, 0, 0, 0, 801, 802, 3, 166, 83, 0, 802, 803, 5, 4, 0, 0, 803,
53, 1, 0, 0, 0, 804, 816, 3, 184, 92, 0, 805, 806, 5, 3, 0, 0, 806, 811,
3, 188, 94, 0, 807, 808, 5, 5, 0, 0, 808, 810, 3, 188, 94, 0, 809, 807,
1, 0, 0, 0, 810, 813, 1, 0, 0, 0, 811, 809, 1, 0, 0, 0, 811, 812, 1, 0,
0, 0, 812, 814, 1, 0, 0, 0, 813, 811, 1, 0, 0, 0, 814, 815, 5, 4, 0, 0,
815, 817, 1, 0, 0, 0, 816, 805, 1, 0, 0, 0, 816, 817, 1, 0, 0, 0, 817,
818, 1, 0, 0, 0, 818, 819, 5, 33, 0, 0, 819, 820, 5, 3, 0, 0, 820, 821,
3, 82, 41, 0, 821, 822, 5, 4, 0, 0, 822, 55, 1, 0, 0, 0, 823, 825, 3, 48,
24, 0, 824, 823, 1, 0, 0, 0, 824, 825, 1, 0, 0, 0, 825, 826, 1, 0, 0, 0,
826, 827, 5, 59, 0, 0, 827, 828, 5, 75, 0, 0, 828, 831, 3, 114, 57, 0,
829, 830, 5, 148, 0, 0, 830, 832, 3, 64, 32, 0, 831, 829, 1, 0, 0, 0, 831,
832, 1, 0, 0, 0, 832, 834, 1, 0, 0, 0, 833, 835, 3, 72, 36, 0, 834, 833,
1, 0, 0, 0, 834, 835, 1, 0, 0, 0, 835, 57, 1, 0, 0, 0, 836, 838, 3, 48,
24, 0, 837, 836, 1, 0, 0, 0, 837, 838, 1, 0, 0, 0, 838, 839, 1, 0, 0, 0,
839, 840, 5, 59, 0, 0, 840, 841, 5, 75, 0, 0, 841, 844, 3, 114, 57, 0,
842, 843, 5, 148, 0, 0, 843, 845, 3, 64, 32, 0, 844, 842, 1, 0, 0, 0, 844,
845, 1, 0, 0, 0, 845, 847, 1, 0, 0, 0, 846, 848, 3, 72, 36, 0, 847, 846,
1, 0, 0, 0, 847, 848, 1, 0, 0, 0, 848, 853, 1, 0, 0, 0, 849, 851, 3, 136,
68, 0, 850, 849, 1, 0, 0, 0, 850, 851, 1, 0, 0, 0, 851, 852, 1, 0, 0, 0,
852, 854, 3, 138, 69, 0, 853, 850, 1, 0, 0, 0, 853, 854, 1, 0, 0, 0, 854,
59, 1, 0, 0, 0, 855, 857, 5, 61, 0, 0, 856, 858, 5, 55, 0, 0, 857, 856,
1, 0, 0, 0, 857, 858, 1, 0, 0, 0, 858, 859, 1, 0, 0, 0, 859, 860, 3, 182,
91, 0, 860, 61, 1, 0, 0, 0, 861, 862, 5, 63, 0, 0, 862, 865, 7, 9, 0, 0,
863, 864, 5, 80, 0, 0, 864, 866, 5, 70, 0, 0, 865, 863, 1, 0, 0, 0, 865,
866, 1, 0, 0, 0, 866, 870, 1, 0, 0, 0, 867, 868, 3, 182, 91, 0, 868, 869,
5, 2, 0, 0, 869, 871, 1, 0, 0, 0, 870, 867, 1, 0, 0, 0, 870, 871, 1, 0,
0, 0, 871, 872, 1, 0, 0, 0, 872, 873, 3, 224, 112, 0, 873, 63, 1, 0, 0,
0, 874, 875, 6, 32, -1, 0, 875, 963, 3, 68, 34, 0, 876, 963, 5, 187, 0,
0, 877, 878, 3, 182, 91, 0, 878, 879, 5, 2, 0, 0, 879, 881, 1, 0, 0, 0,
880, 877, 1, 0, 0, 0, 880, 881, 1, 0, 0, 0, 881, 882, 1, 0, 0, 0, 882,
883, 3, 184, 92, 0, 883, 884, 5, 2, 0, 0, 884, 886, 1, 0, 0, 0, 885, 880,
1, 0, 0, 0, 885, 886, 1, 0, 0, 0, 886, 887, 1, 0, 0, 0, 887, 963, 3, 188,
94, 0, 888, 889, 3, 168, 84, 0, 889, 890, 3, 64, 32, 21, 890, 963, 1, 0,
0, 0, 891, 892, 3, 180, 90, 0, 892, 905, 5, 3, 0, 0, 893, 895, 5, 62, 0,
0, 894, 893, 1, 0, 0, 0, 894, 895, 1, 0, 0, 0, 895, 896, 1, 0, 0, 0, 896,
901, 3, 64, 32, 0, 897, 898, 5, 5, 0, 0, 898, 900, 3, 64, 32, 0, 899, 897,
1, 0, 0, 0, 900, 903, 1, 0, 0, 0, 901, 899, 1, 0, 0, 0, 901, 902, 1, 0,
0, 0, 902, 906, 1, 0, 0, 0, 903, 901, 1, 0, 0, 0, 904, 906, 5, 7, 0, 0,
905, 894, 1, 0, 0, 0, 905, 904, 1, 0, 0, 0, 905, 906, 1, 0, 0, 0, 906,
907, 1, 0, 0, 0, 907, 909, 5, 4, 0, 0, 908, 910, 3, 118, 59, 0, 909, 908,
1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 912, 1, 0, 0, 0, 911, 913, 3, 122,
61, 0, 912, 911, 1, 0, 0, 0, 912, 913, 1, 0, 0, 0, 913, 963, 1, 0, 0, 0,
914, 915, 5, 3, 0, 0, 915, 920, 3, 64, 32, 0, 916, 917, 5, 5, 0, 0, 917,
919, 3, 64, 32, 0, 918, 916, 1, 0, 0, 0, 919, 922, 1, 0, 0, 0, 920, 918,
1, 0, 0, 0, 920, 921, 1, 0, 0, 0, 921, 923, 1, 0, 0, 0, 922, 920, 1, 0,
0, 0, 923, 924, 5, 4, 0, 0, 924, 963, 1, 0, 0, 0, 925, 926, 5, 43, 0, 0,
926, 927, 5, 3, 0, 0, 927, 928, 3, 64, 32, 0, 928, 929, 5, 33, 0, 0, 929,
930, 3, 30, 15, 0, 930, 931, 5, 4, 0, 0, 931, 963, 1, 0, 0, 0, 932, 934,
5, 102, 0, 0, 933, 932, 1, 0, 0, 0, 933, 934, 1, 0, 0, 0, 934, 935, 1,
0, 0, 0, 935, 937, 5, 70, 0, 0, 936, 933, 1, 0, 0, 0, 936, 937, 1, 0, 0,
0, 937, 938, 1, 0, 0, 0, 938, 939, 5, 3, 0, 0, 939, 940, 3, 82, 41, 0,
940, 941, 5, 4, 0, 0, 941, 963, 1, 0, 0, 0, 942, 944, 5, 42, 0, 0, 943,
945, 3, 64, 32, 0, 944, 943, 1, 0, 0, 0, 944, 945, 1, 0, 0, 0, 945, 951,
1, 0, 0, 0, 946, 947, 5, 147, 0, 0, 947, 948, 3, 64, 32, 0, 948, 949, 5,
135, 0, 0, 949, 950, 3, 64, 32, 0, 950, 952, 1, 0, 0, 0, 951, 946, 1, 0,
0, 0, 952, 953, 1, 0, 0, 0, 953, 951, 1, 0, 0, 0, 953, 954, 1, 0, 0, 0,
954, 957, 1, 0, 0, 0, 955, 956, 5, 65, 0, 0, 956, 958, 3, 64, 32, 0, 957,
955, 1, 0, 0, 0, 957, 958, 1, 0, 0, 0, 958, 959, 1, 0, 0, 0, 959, 960,
5, 66, 0, 0, 960, 963, 1, 0, 0, 0, 961, 963, 3, 66, 33, 0, 962, 874, 1,
0, 0, 0, 962, 876, 1, 0, 0, 0, 962, 885, 1, 0, 0, 0, 962, 888, 1, 0, 0,
0, 962, 891, 1, 0, 0, 0, 962, 914, 1, 0, 0, 0, 962, 925, 1, 0, 0, 0, 962,
936, 1, 0, 0, 0, 962, 942, 1, 0, 0, 0, 962, 961, 1, 0, 0, 0, 963, 1083,
1, 0, 0, 0, 964, 965, 10, 20, 0, 0, 965, 966, 5, 11, 0, 0, 966, 1082, 3,
64, 32, 21, 967, 968, 10, 19, 0, 0, 968, 969, 7, 10, 0, 0, 969, 1082, 3,
64, 32, 20, 970, 971, 10, 18, 0, 0, 971, 972, 7, 4, 0, 0, 972, 1082, 3,
64, 32, 19, 973, 974, 10, 17, 0, 0, 974, 975, 7, 11, 0, 0, 975, 1082, 3,
64, 32, 18, 976, 977, 10, 16, 0, 0, 977, 978, 7, 12, 0, 0, 978, 1082, 3,
64, 32, 17, 979, 992, 10, 15, 0, 0, 980, 993, 5, 6, 0, 0, 981, 993, 5,
22, 0, 0, 982, 993, 5, 23, 0, 0, 983, 993, 5, 24, 0, 0, 984, 993, 5, 92,
0, 0, 985, 986, 5, 92, 0, 0, 986, 993, 5, 102, 0, 0, 987, 993, 5, 83, 0,
0, 988, 993, 5, 97, 0, 0, 989, 993, 5, 77, 0, 0, 990, 993, 5, 99, 0, 0,
991, 993, 5, 118, 0, 0, 992, 980, 1, 0, 0, 0, 992, 981, 1, 0, 0, 0, 992,
982, 1, 0, 0, 0, 992, 983, 1, 0, 0, 0, 992, 984, 1, 0, 0, 0, 992, 985,
1, 0, 0, 0, 992, 987, 1, 0, 0, 0, 992, 988, 1, 0, 0, 0, 992, 989, 1, 0,
0, 0, 992, 990, 1, 0, 0, 0, 992, 991, 1, 0, 0, 0, 993, 994, 1, 0, 0, 0,
994, 1082, 3, 64, 32, 16, 995, 996, 10, 14, 0, 0, 996, 997, 5, 32, 0, 0,
997, 1082, 3, 64, 32, 15, 998, 999, 10, 13, 0, 0, 999, 1000, 5, 108, 0,
0, 1000, 1082, 3, 64, 32, 14, 1001, 1002, 10, 6, 0, 0, 1002, 1004, 5, 92,
0, 0, 1003, 1005, 5, 102, 0, 0, 1004, 1003, 1, 0, 0, 0, 1004, 1005, 1,
0, 0, 0, 1005, 1006, 1, 0, 0, 0, 1006, 1082, 3, 64, 32, 7, 1007, 1009,
10, 5, 0, 0, 1008, 1010, 5, 102, 0, 0, 1009, 1008, 1, 0, 0, 0, 1009, 1010,
1, 0, 0, 0, 1010, 1011, 1, 0, 0, 0, 1011, 1012, 5, 39, 0, 0, 1012, 1013,
3, 64, 32, 0, 1013, 1014, 5, 32, 0, 0, 1014, 1015, 3, 64, 32, 6, 1015,
1082, 1, 0, 0, 0, 1016, 1017, 10, 9, 0, 0, 1017, 1018, 5, 45, 0, 0, 1018,
1082, 3, 190, 95, 0, 1019, 1021, 10, 8, 0, 0, 1020, 1022, 5, 102, 0, 0,
1021, 1020, 1, 0, 0, 0, 1021, 1022, 1, 0, 0, 0, 1022, 1023, 1, 0, 0, 0,
1023, 1024, 7, 13, 0, 0, 1024, 1027, 3, 64, 32, 0, 1025, 1026, 5, 67, 0,
0, 1026, 1028, 3, 64, 32, 0, 1027, 1025, 1, 0, 0, 0, 1027, 1028, 1, 0,
0, 0, 1028, 1082, 1, 0, 0, 0, 1029, 1034, 10, 7, 0, 0, 1030, 1035, 5, 93,
0, 0, 1031, 1035, 5, 103, 0, 0, 1032, 1033, 5, 102, 0, 0, 1033, 1035, 5,
104, 0, 0, 1034, 1030, 1, 0, 0, 0, 1034, 1031, 1, 0, 0, 0, 1034, 1032,
1, 0, 0, 0, 1035, 1082, 1, 0, 0, 0, 1036, 1038, 10, 4, 0, 0, 1037, 1039,
5, 102, 0, 0, 1038, 1037, 1, 0, 0, 0, 1038, 1039, 1, 0, 0, 0, 1039, 1040,
1, 0, 0, 0, 1040, 1079, 5, 83, 0, 0, 1041, 1051, 5, 3, 0, 0, 1042, 1052,
3, 82, 41, 0, 1043, 1048, 3, 64, 32, 0, 1044, 1045, 5, 5, 0, 0, 1045, 1047,
3, 64, 32, 0, 1046, 1044, 1, 0, 0, 0, 1047, 1050, 1, 0, 0, 0, 1048, 1046,
1, 0, 0, 0, 1048, 1049, 1, 0, 0, 0, 1049, 1052, 1, 0, 0, 0, 1050, 1048,
1, 0, 0, 0, 1051, 1042, 1, 0, 0, 0, 1051, 1043, 1, 0, 0, 0, 1051, 1052,
1, 0, 0, 0, 1052, 1053, 1, 0, 0, 0, 1053, 1080, 5, 4, 0, 0, 1054, 1055,
3, 182, 91, 0, 1055, 1056, 5, 2, 0, 0, 1056, 1058, 1, 0, 0, 0, 1057, 1054,
1, 0, 0, 0, 1057, 1058, 1, 0, 0, 0, 1058, 1059, 1, 0, 0, 0, 1059, 1080,
3, 184, 92, 0, 1060, 1061, 3, 182, 91, 0, 1061, 1062, 5, 2, 0, 0, 1062,
1064, 1, 0, 0, 0, 1063, 1060, 1, 0, 0, 0, 1063, 1064, 1, 0, 0, 0, 1064,
1065, 1, 0, 0, 0, 1065, 1066, 3, 222, 111, 0, 1066, 1075, 5, 3, 0, 0, 1067,
1072, 3, 64, 32, 0, 1068, 1069, 5, 5, 0, 0, 1069, 1071, 3, 64, 32, 0, 1070,
1068, 1, 0, 0, 0, 1071, 1074, 1, 0, 0, 0, 1072, 1070, 1, 0, 0, 0, 1072,
1073, 1, 0, 0, 0, 1073, 1076, 1, 0, 0, 0, 1074, 1072, 1, 0, 0, 0, 1075,
1067, 1, 0, 0, 0, 1075, 1076, 1, 0, 0, 0, 1076, 1077, 1, 0, 0, 0, 1077,
1078, 5, 4, 0, 0, 1078, 1080, 1, 0, 0, 0, 1079, 1041, 1, 0, 0, 0, 1079,
1057, 1, 0, 0, 0, 1079, 1063, 1, 0, 0, 0, 1080, 1082, 1, 0, 0, 0, 1081,
964, 1, 0, 0, 0, 1081, 967, 1, 0, 0, 0, 1081, 970, 1, 0, 0, 0, 1081, 973,
1, 0, 0, 0, 1081, 976, 1, 0, 0, 0, 1081, 979, 1, 0, 0, 0, 1081, 995, 1,
0, 0, 0, 1081, 998, 1, 0, 0, 0, 1081, 1001, 1, 0, 0, 0, 1081, 1007, 1,
0, 0, 0, 1081, 1016, 1, 0, 0, 0, 1081, 1019, 1, 0, 0, 0, 1081, 1029, 1,
0, 0, 0, 1081, 1036, 1, 0, 0, 0, 1082, 1085, 1, 0, 0, 0, 1083, 1081, 1,
0, 0, 0, 1083, 1084, 1, 0, 0, 0, 1084, 65, 1, 0, 0, 0, 1085, 1083, 1, 0,
0, 0, 1086, 1087, 5, 115, 0, 0, 1087, 1092, 5, 3, 0, 0, 1088, 1093, 5,
81, 0, 0, 1089, 1090, 7, 14, 0, 0, 1090, 1091, 5, 5, 0, 0, 1091, 1093,
3, 170, 85, 0, 1092, 1088, 1, 0, 0, 0, 1092, 1089, 1, 0, 0, 0, 1093, 1094,
1, 0, 0, 0, 1094, 1095, 5, 4, 0, 0, 1095, 67, 1, 0, 0, 0, 1096, 1097, 7,
15, 0, 0, 1097, 69, 1, 0, 0, 0, 1098, 1100, 3, 48, 24, 0, 1099, 1098, 1,
0, 0, 0, 1099, 1100, 1, 0, 0, 0, 1100, 1106, 1, 0, 0, 0, 1101, 1107, 5,
88, 0, 0, 1102, 1107, 5, 122, 0, 0, 1103, 1104, 5, 88, 0, 0, 1104, 1105,
5, 108, 0, 0, 1105, 1107, 7, 8, 0, 0, 1106, 1101, 1, 0, 0, 0, 1106, 1102,
1, 0, 0, 0, 1106, 1103, 1, 0, 0, 0, 1107, 1108, 1, 0, 0, 0, 1108, 1112,
5, 91, 0, 0, 1109, 1110, 3, 182, 91, 0, 1110, 1111, 5, 2, 0, 0, 1111, 1113,
1, 0, 0, 0, 1112, 1109, 1, 0, 0, 0, 1112, 1113, 1, 0, 0, 0, 1113, 1114,
1, 0, 0, 0, 1114, 1117, 3, 184, 92, 0, 1115, 1116, 5, 33, 0, 0, 1116, 1118,
3, 206, 103, 0, 1117, 1115, 1, 0, 0, 0, 1117, 1118, 1, 0, 0, 0, 1118, 1130,
1, 0, 0, 0, 1119, 1120, 5, 3, 0, 0, 1120, 1125, 3, 188, 94, 0, 1121, 1122,
5, 5, 0, 0, 1122, 1124, 3, 188, 94, 0, 1123, 1121, 1, 0, 0, 0, 1124, 1127,
1, 0, 0, 0, 1125, 1123, 1, 0, 0, 0, 1125, 1126, 1, 0, 0, 0, 1126, 1128,
1, 0, 0, 0, 1127, 1125, 1, 0, 0, 0, 1128, 1129, 5, 4, 0, 0, 1129, 1131,
1, 0, 0, 0, 1130, 1119, 1, 0, 0, 0, 1130, 1131, 1, 0, 0, 0, 1131, 1168,
1, 0, 0, 0, 1132, 1133, 5, 144, 0, 0, 1133, 1134, 5, 3, 0, 0, 1134, 1139,
3, 64, 32, 0, 1135, 1136, 5, 5, 0, 0, 1136, 1138, 3, 64, 32, 0, 1137, 1135,
1, 0, 0, 0, 1138, 1141, 1, 0, 0, 0, 1139, 1137, 1, 0, 0, 0, 1139, 1140,
1, 0, 0, 0, 1140, 1142, 1, 0, 0, 0, 1141, 1139, 1, 0, 0, 0, 1142, 1157,
5, 4, 0, 0, 1143, 1144, 5, 5, 0, 0, 1144, 1145, 5, 3, 0, 0, 1145, 1150,
3, 64, 32, 0, 1146, 1147, 5, 5, 0, 0, 1147, 1149, 3, 64, 32, 0, 1148, 1146,
1, 0, 0, 0, 1149, 1152, 1, 0, 0, 0, 1150, 1148, 1, 0, 0, 0, 1150, 1151,
1, 0, 0, 0, 1151, 1153, 1, 0, 0, 0, 1152, 1150, 1, 0, 0, 0, 1153, 1154,
5, 4, 0, 0, 1154, 1156, 1, 0, 0, 0, 1155, 1143, 1, 0, 0, 0, 1156, 1159,
1, 0, 0, 0, 1157, 1155, 1, 0, 0, 0, 1157, 1158, 1, 0, 0, 0, 1158, 1162,
1, 0, 0, 0, 1159, 1157, 1, 0, 0, 0, 1160, 1162, 3, 82, 41, 0, 1161, 1132,
1, 0, 0, 0, 1161, 1160, 1, 0, 0, 0, 1162, 1164, 1, 0, 0, 0, 1163, 1165,
3, 74, 37, 0, 1164, 1163, 1, 0, 0, 0, 1164, 1165, 1, 0, 0, 0, 1165, 1169,
1, 0, 0, 0, 1166, 1167, 5, 56, 0, 0, 1167, 1169, 5, 144, 0, 0, 1168, 1161,
1, 0, 0, 0, 1168, 1166, 1, 0, 0, 0, 1169, 1171, 1, 0, 0, 0, 1170, 1172,
3, 72, 36, 0, 1171, 1170, 1, 0, 0, 0, 1171, 1172, 1, 0, 0, 0, 1172, 71,
1, 0, 0, 0, 1173, 1174, 5, 124, 0, 0, 1174, 1179, 3, 96, 48, 0, 1175, 1176,
5, 5, 0, 0, 1176, 1178, 3, 96, 48, 0, 1177, 1175, 1, 0, 0, 0, 1178, 1181,
1, 0, 0, 0, 1179, 1177, 1, 0, 0, 0, 1179, 1180, 1, 0, 0, 0, 1180, 73, 1,
0, 0, 0, 1181, 1179, 1, 0, 0, 0, 1182, 1183, 5, 107, 0, 0, 1183, 1198,
5, 48, 0, 0, 1184, 1185, 5, 3, 0, 0, 1185, 1190, 3, 24, 12, 0, 1186, 1187,
5, 5, 0, 0, 1187, 1189, 3, 24, 12, 0, 1188, 1186, 1, 0, 0, 0, 1189, 1192,
1, 0, 0, 0, 1190, 1188, 1, 0, 0, 0, 1190, 1191, 1, 0, 0, 0, 1191, 1193,
1, 0, 0, 0, 1192, 1190, 1, 0, 0, 0, 1193, 1196, 5, 4, 0, 0, 1194, 1195,
5, 148, 0, 0, 1195, 1197, 3, 64, 32, 0, 1196, 1194, 1, 0, 0, 0, 1196, 1197,
1, 0, 0, 0, 1197, 1199, 1, 0, 0, 0, 1198, 1184, 1, 0, 0, 0, 1198, 1199,
1, 0, 0, 0, 1199, 1200, 1, 0, 0, 0, 1200, 1227, 5, 183, 0, 0, 1201, 1228,
5, 184, 0, 0, 1202, 1203, 5, 141, 0, 0, 1203, 1206, 5, 131, 0, 0, 1204,
1207, 3, 188, 94, 0, 1205, 1207, 3, 110, 55, 0, 1206, 1204, 1, 0, 0, 0,
1206, 1205, 1, 0, 0, 0, 1207, 1208, 1, 0, 0, 0, 1208, 1209, 5, 6, 0, 0,
1209, 1220, 3, 64, 32, 0, 1210, 1213, 5, 5, 0, 0, 1211, 1214, 3, 188, 94,
0, 1212, 1214, 3, 110, 55, 0, 1213, 1211, 1, 0, 0, 0, 1213, 1212, 1, 0,
0, 0, 1214, 1215, 1, 0, 0, 0, 1215, 1216, 5, 6, 0, 0, 1216, 1217, 3, 64,
32, 0, 1217, 1219, 1, 0, 0, 0, 1218, 1210, 1, 0, 0, 0, 1219, 1222, 1, 0,
0, 0, 1220, 1218, 1, 0, 0, 0, 1220, 1221, 1, 0, 0, 0, 1221, 1225, 1, 0,
0, 0, 1222, 1220, 1, 0, 0, 0, 1223, 1224, 5, 148, 0, 0, 1224, 1226, 3,
64, 32, 0, 1225, 1223, 1, 0, 0, 0, 1225, 1226, 1, 0, 0, 0, 1226, 1228,
1, 0, 0, 0, 1227, 1201, 1, 0, 0, 0, 1227, 1202, 1, 0, 0, 0, 1228, 75, 1,
0, 0, 0, 1229, 1233, 5, 112, 0, 0, 1230, 1231, 3, 182, 91, 0, 1231, 1232,
5, 2, 0, 0, 1232, 1234, 1, 0, 0, 0, 1233, 1230, 1, 0, 0, 0, 1233, 1234,
1, 0, 0, 0, 1234, 1235, 1, 0, 0, 0, 1235, 1242, 3, 202, 101, 0, 1236, 1237,
5, 6, 0, 0, 1237, 1243, 3, 78, 39, 0, 1238, 1239, 5, 3, 0, 0, 1239, 1240,
3, 78, 39, 0, 1240, 1241, 5, 4, 0, 0, 1241, 1243, 1, 0, 0, 0, 1242, 1236,
1, 0, 0, 0, 1242, 1238, 1, 0, 0, 0, 1242, 1243, 1, 0, 0, 0, 1243, 77, 1,
0, 0, 0, 1244, 1248, 3, 34, 17, 0, 1245, 1248, 3, 178, 89, 0, 1246, 1248,
5, 188, 0, 0, 1247, 1244, 1, 0, 0, 0, 1247, 1245, 1, 0, 0, 0, 1247, 1246,
1, 0, 0, 0, 1248, 79, 1, 0, 0, 0, 1249, 1260, 5, 119, 0, 0, 1250, 1261,
3, 190, 95, 0, 1251, 1252, 3, 182, 91, 0, 1252, 1253, 5, 2, 0, 0, 1253,
1255, 1, 0, 0, 0, 1254, 1251, 1, 0, 0, 0, 1254, 1255, 1, 0, 0, 0, 1255,
1258, 1, 0, 0, 0, 1256, 1259, 3, 184, 92, 0, 1257, 1259, 3, 194, 97, 0,
1258, 1256, 1, 0, 0, 0, 1258, 1257, 1, 0, 0, 0, 1259, 1261, 1, 0, 0, 0,
1260, 1250, 1, 0, 0, 0, 1260, 1254, 1, 0, 0, 0, 1260, 1261, 1, 0, 0, 0,
1261, 81, 1, 0, 0, 0, 1262, 1264, 3, 134, 67, 0, 1263, 1262, 1, 0, 0, 0,
1263, 1264, 1, 0, 0, 0, 1264, 1265, 1, 0, 0, 0, 1265, 1271, 3, 86, 43,
0, 1266, 1267, 3, 102, 51, 0, 1267, 1268, 3, 86, 43, 0, 1268, 1270, 1,
0, 0, 0, 1269, 1266, 1, 0, 0, 0, 1270, 1273, 1, 0, 0, 0, 1271, 1269, 1,
0, 0, 0, 1271, 1272, 1, 0, 0, 0, 1272, 1275, 1, 0, 0, 0, 1273, 1271, 1,
0, 0, 0, 1274, 1276, 3, 136, 68, 0, 1275, 1274, 1, 0, 0, 0, 1275, 1276,
1, 0, 0, 0, 1276, 1278, 1, 0, 0, 0, 1277, 1279, 3, 138, 69, 0, 1278, 1277,
1, 0, 0, 0, 1278, 1279, 1, 0, 0, 0, 1279, 83, 1, 0, 0, 0, 1280, 1288, 3,
94, 47, 0, 1281, 1282, 3, 98, 49, 0, 1282, 1284, 3, 94, 47, 0, 1283, 1285,
3, 100, 50, 0, 1284, 1283, 1, 0, 0, 0, 1284, 1285, 1, 0, 0, 0, 1285, 1287,
1, 0, 0, 0, 1286, 1281, 1, 0, 0, 0, 1287, 1290, 1, 0, 0, 0, 1288, 1286,
1, 0, 0, 0, 1288, 1289, 1, 0, 0, 0, 1289, 85, 1, 0, 0, 0, 1290, 1288, 1,
0, 0, 0, 1291, 1293, 5, 130, 0, 0, 1292, 1294, 7, 16, 0, 0, 1293, 1292,
1, 0, 0, 0, 1293, 1294, 1, 0, 0, 0, 1294, 1295, 1, 0, 0, 0, 1295, 1300,
3, 96, 48, 0, 1296, 1297, 5, 5, 0, 0, 1297, 1299, 3, 96, 48, 0, 1298, 1296,
1, 0, 0, 0, 1299, 1302, 1, 0, 0, 0, 1300, 1298, 1, 0, 0, 0, 1300, 1301,
1, 0, 0, 0, 1301, 1315, 1, 0, 0, 0, 1302, 1300, 1, 0, 0, 0, 1303, 1313,
5, 75, 0, 0, 1304, 1309, 3, 94, 47, 0, 1305, 1306, 5, 5, 0, 0, 1306, 1308,
3, 94, 47, 0, 1307, 1305, 1, 0, 0, 0, 1308, 1311, 1, 0, 0, 0, 1309, 1307,
1, 0, 0, 0, 1309, 1310, 1, 0, 0, 0, 1310, 1314, 1, 0, 0, 0, 1311, 1309,
1, 0, 0, 0, 1312, 1314, 3, 84, 42, 0, 1313, 1304, 1, 0, 0, 0, 1313, 1312,
1, 0, 0, 0, 1314, 1316, 1, 0, 0, 0, 1315, 1303, 1, 0, 0, 0, 1315, 1316,
1, 0, 0, 0, 1316, 1319, 1, 0, 0, 0, 1317, 1318, 5, 148, 0, 0, 1318, 1320,
3, 64, 32, 0, 1319, 1317, 1, 0, 0, 0, 1319, 1320, 1, 0, 0, 0, 1320, 1335,
1, 0, 0, 0, 1321, 1322, 5, 78, 0, 0, 1322, 1323, 5, 40, 0, 0, 1323, 1328,
3, 64, 32, 0, 1324, 1325, 5, 5, 0, 0, 1325, 1327, 3, 64, 32, 0, 1326, 1324,
1, 0, 0, 0, 1327, 1330, 1, 0, 0, 0, 1328, 1326, 1, 0, 0, 0, 1328, 1329,
1, 0, 0, 0, 1329, 1333, 1, 0, 0, 0, 1330, 1328, 1, 0, 0, 0, 1331, 1332,
5, 79, 0, 0, 1332, 1334, 3, 64, 32, 0, 1333, 1331, 1, 0, 0, 0, 1333, 1334,
1, 0, 0, 0, 1334, 1336, 1, 0, 0, 0, 1335, 1321, 1, 0, 0, 0, 1335, 1336,
1, 0, 0, 0, 1336, 1351, 1, 0, 0, 0, 1337, 1338, 5, 174, 0, 0, 1338, 1339,
3, 210, 105, 0, 1339, 1340, 5, 33, 0, 0, 1340, 1348, 3, 120, 60, 0, 1341,
1342, 5, 5, 0, 0, 1342, 1343, 3, 210, 105, 0, 1343, 1344, 5, 33, 0, 0,
1344, 1345, 3, 120, 60, 0, 1345, 1347, 1, 0, 0, 0, 1346, 1341, 1, 0, 0,
0, 1347, 1350, 1, 0, 0, 0, 1348, 1346, 1, 0, 0, 0, 1348, 1349, 1, 0, 0,
0, 1349, 1352, 1, 0, 0, 0, 1350, 1348, 1, 0, 0, 0, 1351, 1337, 1, 0, 0,
0, 1351, 1352, 1, 0, 0, 0, 1352, 1382, 1, 0, 0, 0, 1353, 1354, 5, 144,
0, 0, 1354, 1355, 5, 3, 0, 0, 1355, 1360, 3, 64, 32, 0, 1356, 1357, 5,
5, 0, 0, 1357, 1359, 3, 64, 32, 0, 1358, 1356, 1, 0, 0, 0, 1359, 1362,
1, 0, 0, 0, 1360, 1358, 1, 0, 0, 0, 1360, 1361, 1, 0, 0, 0, 1361, 1363,
1, 0, 0, 0, 1362, 1360, 1, 0, 0, 0, 1363, 1378, 5, 4, 0, 0, 1364, 1365,
5, 5, 0, 0, 1365, 1366, 5, 3, 0, 0, 1366, 1371, 3, 64, 32, 0, 1367, 1368,
5, 5, 0, 0, 1368, 1370, 3, 64, 32, 0, 1369, 1367, 1, 0, 0, 0, 1370, 1373,
1, 0, 0, 0, 1371, 1369, 1, 0, 0, 0, 1371, 1372, 1, 0, 0, 0, 1372, 1374,
1, 0, 0, 0, 1373, 1371, 1, 0, 0, 0, 1374, 1375, 5, 4, 0, 0, 1375, 1377,
1, 0, 0, 0, 1376, 1364, 1, 0, 0, 0, 1377, 1380, 1, 0, 0, 0, 1378, 1376,
1, 0, 0, 0, 1378, 1379, 1, 0, 0, 0, 1379, 1382, 1, 0, 0, 0, 1380, 1378,
1, 0, 0, 0, 1381, 1291, 1, 0, 0, 0, 1381, 1353, 1, 0, 0, 0, 1382, 87, 1,
0, 0, 0, 1383, 1384, 3, 82, 41, 0, 1384, 89, 1, 0, 0, 0, 1385, 1387, 3,
134, 67, 0, 1386, 1385, 1, 0, 0, 0, 1386, 1387, 1, 0, 0, 0, 1387, 1388,
1, 0, 0, 0, 1388, 1390, 3, 86, 43, 0, 1389, 1391, 3, 136, 68, 0, 1390,
1389, 1, 0, 0, 0, 1390, 1391, 1, 0, 0, 0, 1391, 1393, 1, 0, 0, 0, 1392,
1394, 3, 138, 69, 0, 1393, 1392, 1, 0, 0, 0, 1393, 1394, 1, 0, 0, 0, 1394,
91, 1, 0, 0, 0, 1395, 1397, 3, 134, 67, 0, 1396, 1395, 1, 0, 0, 0, 1396,
1397, 1, 0, 0, 0, 1397, 1398, 1, 0, 0, 0, 1398, 1408, 3, 86, 43, 0, 1399,
1401, 5, 139, 0, 0, 1400, 1402, 5, 29, 0, 0, 1401, 1400, 1, 0, 0, 0, 1401,
1402, 1, 0, 0, 0, 1402, 1406, 1, 0, 0, 0, 1403, 1406, 5, 90, 0, 0, 1404,
1406, 5, 68, 0, 0, 1405, 1399, 1, 0, 0, 0, 1405, 1403, 1, 0, 0, 0, 1405,
1404, 1, 0, 0, 0, 1406, 1407, 1, 0, 0, 0, 1407, 1409, 3, 86, 43, 0, 1408,
1405, 1, 0, 0, 0, 1409, 1410, 1, 0, 0, 0, 1410, 1408, 1, 0, 0, 0, 1410,
1411, 1, 0, 0, 0, 1411, 1413, 1, 0, 0, 0, 1412, 1414, 3, 136, 68, 0, 1413,
1412, 1, 0, 0, 0, 1413, 1414, 1, 0, 0, 0, 1414, 1416, 1, 0, 0, 0, 1415,
1417, 3, 138, 69, 0, 1416, 1415, 1, 0, 0, 0, 1416, 1417, 1, 0, 0, 0, 1417,
93, 1, 0, 0, 0, 1418, 1419, 3, 182, 91, 0, 1419, 1420, 5, 2, 0, 0, 1420,
1422, 1, 0, 0, 0, 1421, 1418, 1, 0, 0, 0, 1421, 1422, 1, 0, 0, 0, 1422,
1423, 1, 0, 0, 0, 1423, 1428, 3, 184, 92, 0, 1424, 1426, 5, 33, 0, 0, 1425,
1424, 1, 0, 0, 0, 1425, 1426, 1, 0, 0, 0, 1426, 1427, 1, 0, 0, 0, 1427,
1429, 3, 206, 103, 0, 1428, 1425, 1, 0, 0, 0, 1428, 1429, 1, 0, 0, 0, 1429,
1435, 1, 0, 0, 0, 1430, 1431, 5, 85, 0, 0, 1431, 1432, 5, 40, 0, 0, 1432,
1436, 3, 194, 97, 0, 1433, 1434, 5, 102, 0, 0, 1434, 1436, 5, 85, 0, 0,
1435, 1430, 1, 0, 0, 0, 1435, 1433, 1, 0, 0, 0, 1435, 1436, 1, 0, 0, 0,
1436, 1483, 1, 0, 0, 0, 1437, 1438, 3, 182, 91, 0, 1438, 1439, 5, 2, 0,
0, 1439, 1441, 1, 0, 0, 0, 1440, 1437, 1, 0, 0, 0, 1440, 1441, 1, 0, 0,
0, 1441, 1442, 1, 0, 0, 0, 1442, 1443, 3, 222, 111, 0, 1443, 1444, 5, 3,
0, 0, 1444, 1449, 3, 64, 32, 0, 1445, 1446, 5, 5, 0, 0, 1446, 1448, 3,
64, 32, 0, 1447, 1445, 1, 0, 0, 0, 1448, 1451, 1, 0, 0, 0, 1449, 1447,
1, 0, 0, 0, 1449, 1450, 1, 0, 0, 0, 1450, 1452, 1, 0, 0, 0, 1451, 1449,
1, 0, 0, 0, 1452, 1457, 5, 4, 0, 0, 1453, 1455, 5, 33, 0, 0, 1454, 1453,
1, 0, 0, 0, 1454, 1455, 1, 0, 0, 0, 1455, 1456, 1, 0, 0, 0, 1456, 1458,
3, 206, 103, 0, 1457, 1454, 1, 0, 0, 0, 1457, 1458, 1, 0, 0, 0, 1458, 1483,
1, 0, 0, 0, 1459, 1469, 5, 3, 0, 0, 1460, 1465, 3, 94, 47, 0, 1461, 1462,
5, 5, 0, 0, 1462, 1464, 3, 94, 47, 0, 1463, 1461, 1, 0, 0, 0, 1464, 1467,
1, 0, 0, 0, 1465, 1463, 1, 0, 0, 0, 1465, 1466, 1, 0, 0, 0, 1466, 1470,
1, 0, 0, 0, 1467, 1465, 1, 0, 0, 0, 1468, 1470, 3, 84, 42, 0, 1469, 1460,
1, 0, 0, 0, 1469, 1468, 1, 0, 0, 0, 1470, 1471, 1, 0, 0, 0, 1471, 1472,
5, 4, 0, 0, 1472, 1483, 1, 0, 0, 0, 1473, 1474, 5, 3, 0, 0, 1474, 1475,
3, 82, 41, 0, 1475, 1480, 5, 4, 0, 0, 1476, 1478, 5, 33, 0, 0, 1477, 1476,
1, 0, 0, 0, 1477, 1478, 1, 0, 0, 0, 1478, 1479, 1, 0, 0, 0, 1479, 1481,
3, 206, 103, 0, 1480, 1477, 1, 0, 0, 0, 1480, 1481, 1, 0, 0, 0, 1481, 1483,
1, 0, 0, 0, 1482, 1421, 1, 0, 0, 0, 1482, 1440, 1, 0, 0, 0, 1482, 1459,
1, 0, 0, 0, 1482, 1473, 1, 0, 0, 0, 1483, 95, 1, 0, 0, 0, 1484, 1497, 5,
7, 0, 0, 1485, 1486, 3, 184, 92, 0, 1486, 1487, 5, 2, 0, 0, 1487, 1488,
5, 7, 0, 0, 1488, 1497, 1, 0, 0, 0, 1489, 1494, 3, 64, 32, 0, 1490, 1492,
5, 33, 0, 0, 1491, 1490, 1, 0, 0, 0, 1491, 1492, 1, 0, 0, 0, 1492, 1493,
1, 0, 0, 0, 1493, 1495, 3, 174, 87, 0, 1494, 1491, 1, 0, 0, 0, 1494, 1495,
1, 0, 0, 0, 1495, 1497, 1, 0, 0, 0, 1496, 1484, 1, 0, 0, 0, 1496, 1485,
1, 0, 0, 0, 1496, 1489, 1, 0, 0, 0, 1497, 97, 1, 0, 0, 0, 1498, 1512, 5,
5, 0, 0, 1499, 1501, 5, 100, 0, 0, 1500, 1499, 1, 0, 0, 0, 1500, 1501,
1, 0, 0, 0, 1501, 1508, 1, 0, 0, 0, 1502, 1504, 5, 96, 0, 0, 1503, 1505,
5, 110, 0, 0, 1504, 1503, 1, 0, 0, 0, 1504, 1505, 1, 0, 0, 0, 1505, 1509,
1, 0, 0, 0, 1506, 1509, 5, 87, 0, 0, 1507, 1509, 5, 51, 0, 0, 1508, 1502,
1, 0, 0, 0, 1508, 1506, 1, 0, 0, 0, 1508, 1507, 1, 0, 0, 0, 1508, 1509,
1, 0, 0, 0, 1509, 1510, 1, 0, 0, 0, 1510, 1512, 5, 94, 0, 0, 1511, 1498,
1, 0, 0, 0, 1511, 1500, 1, 0, 0, 0, 1512, 99, 1, 0, 0, 0, 1513, 1514, 5,
107, 0, 0, 1514, 1528, 3, 64, 32, 0, 1515, 1516, 5, 142, 0, 0, 1516, 1517,
5, 3, 0, 0, 1517, 1522, 3, 188, 94, 0, 1518, 1519, 5, 5, 0, 0, 1519, 1521,
3, 188, 94, 0, 1520, 1518, 1, 0, 0, 0, 1521, 1524, 1, 0, 0, 0, 1522, 1520,
1, 0, 0, 0, 1522, 1523, 1, 0, 0, 0, 1523, 1525, 1, 0, 0, 0, 1524, 1522,
1, 0, 0, 0, 1525, 1526, 5, 4, 0, 0, 1526, 1528, 1, 0, 0, 0, 1527, 1513,
1, 0, 0, 0, 1527, 1515, 1, 0, 0, 0, 1528, 101, 1, 0, 0, 0, 1529, 1531,
5, 139, 0, 0, 1530, 1532, 5, 29, 0, 0, 1531, 1530, 1, 0, 0, 0, 1531, 1532,
1, 0, 0, 0, 1532, 1536, 1, 0, 0, 0, 1533, 1536, 5, 90, 0, 0, 1534, 1536,
5, 68, 0, 0, 1535, 1529, 1, 0, 0, 0, 1535, 1533, 1, 0, 0, 0, 1535, 1534,
1, 0, 0, 0, 1536, 103, 1, 0, 0, 0, 1537, 1539, 3, 48, 24, 0, 1538, 1537,
1, 0, 0, 0, 1538, 1539, 1, 0, 0, 0, 1539, 1540, 1, 0, 0, 0, 1540, 1543,
5, 141, 0, 0, 1541, 1542, 5, 108, 0, 0, 1542, 1544, 7, 8, 0, 0, 1543, 1541,
1, 0, 0, 0, 1543, 1544, 1, 0, 0, 0, 1544, 1545, 1, 0, 0, 0, 1545, 1546,
3, 114, 57, 0, 1546, 1547, 5, 131, 0, 0, 1547, 1560, 3, 106, 53, 0, 1548,
1558, 5, 75, 0, 0, 1549, 1554, 3, 94, 47, 0, 1550, 1551, 5, 5, 0, 0, 1551,
1553, 3, 94, 47, 0, 1552, 1550, 1, 0, 0, 0, 1553, 1556, 1, 0, 0, 0, 1554,
1552, 1, 0, 0, 0, 1554, 1555, 1, 0, 0, 0, 1555, 1559, 1, 0, 0, 0, 1556,
1554, 1, 0, 0, 0, 1557, 1559, 3, 84, 42, 0, 1558, 1549, 1, 0, 0, 0, 1558,
1557, 1, 0, 0, 0, 1559, 1561, 1, 0, 0, 0, 1560, 1548, 1, 0, 0, 0, 1560,
1561, 1, 0, 0, 0, 1561, 1564, 1, 0, 0, 0, 1562, 1563, 5, 148, 0, 0, 1563,
1565, 3, 64, 32, 0, 1564, 1562, 1, 0, 0, 0, 1564, 1565, 1, 0, 0, 0, 1565,
1567, 1, 0, 0, 0, 1566, 1568, 3, 72, 36, 0, 1567, 1566, 1, 0, 0, 0, 1567,
1568, 1, 0, 0, 0, 1568, 105, 1, 0, 0, 0, 1569, 1574, 3, 108, 54, 0, 1570,
1571, 5, 5, 0, 0, 1571, 1573, 3, 108, 54, 0, 1572, 1570, 1, 0, 0, 0, 1573,
1576, 1, 0, 0, 0, 1574, 1572, 1, 0, 0, 0, 1574, 1575, 1, 0, 0, 0, 1575,
107, 1, 0, 0, 0, 1576, 1574, 1, 0, 0, 0, 1577, 1580, 3, 188, 94, 0, 1578,
1580, 3, 110, 55, 0, 1579, 1577, 1, 0, 0, 0, 1579, 1578, 1, 0, 0, 0, 1580,
1581, 1, 0, 0, 0, 1581, 1582, 5, 6, 0, 0, 1582, 1583, 3, 64, 32, 0, 1583,
109, 1, 0, 0, 0, 1584, 1585, 5, 3, 0, 0, 1585, 1590, 3, 188, 94, 0, 1586,
1587, 5, 5, 0, 0, 1587, 1589, 3, 188, 94, 0, 1588, 1586, 1, 0, 0, 0, 1589,
1592, 1, 0, 0, 0, 1590, 1588, 1, 0, 0, 0, 1590, 1591, 1, 0, 0, 0, 1591,
1593, 1, 0, 0, 0, 1592, 1590, 1, 0, 0, 0, 1593, 1594, 5, 4, 0, 0, 1594,
111, 1, 0, 0, 0, 1595, 1597, 3, 48, 24, 0, 1596, 1595, 1, 0, 0, 0, 1596,
1597, 1, 0, 0, 0, 1597, 1598, 1, 0, 0, 0, 1598, 1601, 5, 141, 0, 0, 1599,
1600, 5, 108, 0, 0, 1600, 1602, 7, 8, 0, 0, 1601, 1599, 1, 0, 0, 0, 1601,
1602, 1, 0, 0, 0, 1602, 1603, 1, 0, 0, 0, 1603, 1604, 3, 114, 57, 0, 1604,
1607, 5, 131, 0, 0, 1605, 1608, 3, 188, 94, 0, 1606, 1608, 3, 110, 55,
0, 1607, 1605, 1, 0, 0, 0, 1607, 1606, 1, 0, 0, 0, 1608, 1609, 1, 0, 0,
0, 1609, 1610, 5, 6, 0, 0, 1610, 1621, 3, 64, 32, 0, 1611, 1614, 5, 5,
0, 0, 1612, 1615, 3, 188, 94, 0, 1613, 1615, 3, 110, 55, 0, 1614, 1612,
1, 0, 0, 0, 1614, 1613, 1, 0, 0, 0, 1615, 1616, 1, 0, 0, 0, 1616, 1617,
5, 6, 0, 0, 1617, 1618, 3, 64, 32, 0, 1618, 1620, 1, 0, 0, 0, 1619, 1611,
1, 0, 0, 0, 1620, 1623, 1, 0, 0, 0, 1621, 1619, 1, 0, 0, 0, 1621, 1622,
1, 0, 0, 0, 1622, 1626, 1, 0, 0, 0, 1623, 1621, 1, 0, 0, 0, 1624, 1625,
5, 148, 0, 0, 1625, 1627, 3, 64, 32, 0, 1626, 1624, 1, 0, 0, 0, 1626, 1627,
1, 0, 0, 0, 1627, 1629, 1, 0, 0, 0, 1628, 1630, 3, 72, 36, 0, 1629, 1628,
1, 0, 0, 0, 1629, 1630, 1, 0, 0, 0, 1630, 1635, 1, 0, 0, 0, 1631, 1633,
3, 136, 68, 0, 1632, 1631, 1, 0, 0, 0, 1632, 1633, 1, 0, 0, 0, 1633, 1634,
1, 0, 0, 0, 1634, 1636, 3, 138, 69, 0, 1635, 1632, 1, 0, 0, 0, 1635, 1636,
1, 0, 0, 0, 1636, 113, 1, 0, 0, 0, 1637, 1638, 3, 182, 91, 0, 1638, 1639,
5, 2, 0, 0, 1639, 1641, 1, 0, 0, 0, 1640, 1637, 1, 0, 0, 0, 1640, 1641,
1, 0, 0, 0, 1641, 1642, 1, 0, 0, 0, 1642, 1645, 3, 184, 92, 0, 1643, 1644,
5, 33, 0, 0, 1644, 1646, 3, 212, 106, 0, 1645, 1643, 1, 0, 0, 0, 1645,
1646, 1, 0, 0, 0, 1646, 1652, 1, 0, 0, 0, 1647, 1648, 5, 85, 0, 0, 1648,
1649, 5, 40, 0, 0, 1649, 1653, 3, 194, 97, 0, 1650, 1651, 5, 102, 0, 0,
1651, 1653, 5, 85, 0, 0, 1652, 1647, 1, 0, 0, 0, 1652, 1650, 1, 0, 0, 0,
1652, 1653, 1, 0, 0, 0, 1653, 115, 1, 0, 0, 0, 1654, 1656, 5, 143, 0, 0,
1655, 1657, 3, 182, 91, 0, 1656, 1655, 1, 0, 0, 0, 1656, 1657, 1, 0, 0,
0, 1657, 1660, 1, 0, 0, 0, 1658, 1659, 5, 91, 0, 0, 1659, 1661, 3, 214,
107, 0, 1660, 1658, 1, 0, 0, 0, 1660, 1661, 1, 0, 0, 0, 1661, 117, 1, 0,
0, 0, 1662, 1663, 5, 178, 0, 0, 1663, 1664, 5, 3, 0, 0, 1664, 1665, 5,
148, 0, 0, 1665, 1666, 3, 64, 32, 0, 1666, 1667, 5, 4, 0, 0, 1667, 119,
1, 0, 0, 0, 1668, 1670, 5, 3, 0, 0, 1669, 1671, 3, 216, 108, 0, 1670, 1669,
1, 0, 0, 0, 1670, 1671, 1, 0, 0, 0, 1671, 1682, 1, 0, 0, 0, 1672, 1673,
5, 153, 0, 0, 1673, 1674, 5, 40, 0, 0, 1674, 1679, 3, 64, 32, 0, 1675,
1676, 5, 5, 0, 0, 1676, 1678, 3, 64, 32, 0, 1677, 1675, 1, 0, 0, 0, 1678,
1681, 1, 0, 0, 0, 1679, 1677, 1, 0, 0, 0, 1679, 1680, 1, 0, 0, 0, 1680,
1683, 1, 0, 0, 0, 1681, 1679, 1, 0, 0, 0, 1682, 1672, 1, 0, 0, 0, 1682,
1683, 1, 0, 0, 0, 1683, 1684, 1, 0, 0, 0, 1684, 1685, 5, 109, 0, 0, 1685,
1686, 5, 40, 0, 0, 1686, 1691, 3, 140, 70, 0, 1687, 1688, 5, 5, 0, 0, 1688,
1690, 3, 140, 70, 0, 1689, 1687, 1, 0, 0, 0, 1690, 1693, 1, 0, 0, 0, 1691,
1689, 1, 0, 0, 0, 1691, 1692, 1, 0, 0, 0, 1692, 1695, 1, 0, 0, 0, 1693,
1691, 1, 0, 0, 0, 1694, 1696, 3, 124, 62, 0, 1695, 1694, 1, 0, 0, 0, 1695,
1696, 1, 0, 0, 0, 1696, 1697, 1, 0, 0, 0, 1697, 1698, 5, 4, 0, 0, 1698,
121, 1, 0, 0, 0, 1699, 1733, 5, 152, 0, 0, 1700, 1734, 3, 210, 105, 0,
1701, 1703, 5, 3, 0, 0, 1702, 1704, 3, 216, 108, 0, 1703, 1702, 1, 0, 0,
0, 1703, 1704, 1, 0, 0, 0, 1704, 1715, 1, 0, 0, 0, 1705, 1706, 5, 153,
0, 0, 1706, 1707, 5, 40, 0, 0, 1707, 1712, 3, 64, 32, 0, 1708, 1709, 5,
5, 0, 0, 1709, 1711, 3, 64, 32, 0, 1710, 1708, 1, 0, 0, 0, 1711, 1714,
1, 0, 0, 0, 1712, 1710, 1, 0, 0, 0, 1712, 1713, 1, 0, 0, 0, 1713, 1716,
1, 0, 0, 0, 1714, 1712, 1, 0, 0, 0, 1715, 1705, 1, 0, 0, 0, 1715, 1716,
1, 0, 0, 0, 1716, 1727, 1, 0, 0, 0, 1717, 1718, 5, 109, 0, 0, 1718, 1719,
5, 40, 0, 0, 1719, 1724, 3, 140, 70, 0, 1720, 1721, 5, 5, 0, 0, 1721, 1723,
3, 140, 70, 0, 1722, 1720, 1, 0, 0, 0, 1723, 1726, 1, 0, 0, 0, 1724, 1722,
1, 0, 0, 0, 1724, 1725, 1, 0, 0, 0, 1725, 1728, 1, 0, 0, 0, 1726, 1724,
1, 0, 0, 0, 1727, 1717, 1, 0, 0, 0, 1727, 1728, 1, 0, 0, 0, 1728, 1730,
1, 0, 0, 0, 1729, 1731, 3, 124, 62, 0, 1730, 1729, 1, 0, 0, 0, 1730, 1731,
1, 0, 0, 0, 1731, 1732, 1, 0, 0, 0, 1732, 1734, 5, 4, 0, 0, 1733, 1700,
1, 0, 0, 0, 1733, 1701, 1, 0, 0, 0, 1734, 123, 1, 0, 0, 0, 1735, 1743,
3, 126, 63, 0, 1736, 1737, 5, 180, 0, 0, 1737, 1738, 5, 101, 0, 0, 1738,
1744, 5, 182, 0, 0, 1739, 1740, 5, 157, 0, 0, 1740, 1744, 5, 127, 0, 0,
1741, 1744, 5, 78, 0, 0, 1742, 1744, 5, 181, 0, 0, 1743, 1736, 1, 0, 0,
0, 1743, 1739, 1, 0, 0, 0, 1743, 1741, 1, 0, 0, 0, 1743, 1742, 1, 0, 0,
0, 1743, 1744, 1, 0, 0, 0, 1744, 125, 1, 0, 0, 0, 1745, 1752, 7, 17, 0,
0, 1746, 1753, 3, 148, 74, 0, 1747, 1748, 5, 39, 0, 0, 1748, 1749, 3, 144,
72, 0, 1749, 1750, 5, 32, 0, 0, 1750, 1751, 3, 146, 73, 0, 1751, 1753,
1, 0, 0, 0, 1752, 1746, 1, 0, 0, 0, 1752, 1747, 1, 0, 0, 0, 1753, 127,
1, 0, 0, 0, 1754, 1755, 3, 218, 109, 0, 1755, 1765, 5, 3, 0, 0, 1756, 1761,
3, 64, 32, 0, 1757, 1758, 5, 5, 0, 0, 1758, 1760, 3, 64, 32, 0, 1759, 1757,
1, 0, 0, 0, 1760, 1763, 1, 0, 0, 0, 1761, 1759, 1, 0, 0, 0, 1761, 1762,
1, 0, 0, 0, 1762, 1766, 1, 0, 0, 0, 1763, 1761, 1, 0, 0, 0, 1764, 1766,
5, 7, 0, 0, 1765, 1756, 1, 0, 0, 0, 1765, 1764, 1, 0, 0, 0, 1766, 1767,
1, 0, 0, 0, 1767, 1768, 5, 4, 0, 0, 1768, 129, 1, 0, 0, 0, 1769, 1770,
3, 220, 110, 0, 1770, 1783, 5, 3, 0, 0, 1771, 1773, 5, 62, 0, 0, 1772,
1771, 1, 0, 0, 0, 1772, 1773, 1, 0, 0, 0, 1773, 1774, 1, 0, 0, 0, 1774,
1779, 3, 64, 32, 0, 1775, 1776, 5, 5, 0, 0, 1776, 1778, 3, 64, 32, 0, 1777,
1775, 1, 0, 0, 0, 1778, 1781, 1, 0, 0, 0, 1779, 1777, 1, 0, 0, 0, 1779,
1780, 1, 0, 0, 0, 1780, 1784, 1, 0, 0, 0, 1781, 1779, 1, 0, 0, 0, 1782,
1784, 5, 7, 0, 0, 1783, 1772, 1, 0, 0, 0, 1783, 1782, 1, 0, 0, 0, 1783,
1784, 1, 0, 0, 0, 1784, 1785, 1, 0, 0, 0, 1785, 1787, 5, 4, 0, 0, 1786,
1788, 3, 118, 59, 0, 1787, 1786, 1, 0, 0, 0, 1787, 1788, 1, 0, 0, 0, 1788,
131, 1, 0, 0, 0, 1789, 1790, 3, 150, 75, 0, 1790, 1800, 5, 3, 0, 0, 1791,
1796, 3, 64, 32, 0, 1792, 1793, 5, 5, 0, 0, 1793, 1795, 3, 64, 32, 0, 1794,
1792, 1, 0, 0, 0, 1795, 1798, 1, 0, 0, 0, 1796, 1794, 1, 0, 0, 0, 1796,
1797, 1, 0, 0, 0, 1797, 1801, 1, 0, 0, 0, 1798, 1796, 1, 0, 0, 0, 1799,
1801, 5, 7, 0, 0, 1800, 1791, 1, 0, 0, 0, 1800, 1799, 1, 0, 0, 0, 1800,
1801, 1, 0, 0, 0, 1801, 1802, 1, 0, 0, 0, 1802, 1804, 5, 4, 0, 0, 1803,
1805, 3, 118, 59, 0, 1804, 1803, 1, 0, 0, 0, 1804, 1805, 1, 0, 0, 0, 1805,
1806, 1, 0, 0, 0, 1806, 1809, 5, 152, 0, 0, 1807, 1810, 3, 120, 60, 0,
1808, 1810, 3, 210, 105, 0, 1809, 1807, 1, 0, 0, 0, 1809, 1808, 1, 0, 0,
0, 1810, 133, 1, 0, 0, 0, 1811, 1813, 5, 149, 0, 0, 1812, 1814, 5, 116,
0, 0, 1813, 1812, 1, 0, 0, 0, 1813, 1814, 1, 0, 0, 0, 1814, 1815, 1, 0,
0, 0, 1815, 1820, 3, 54, 27, 0, 1816, 1817, 5, 5, 0, 0, 1817, 1819, 3,
54, 27, 0, 1818, 1816, 1, 0, 0, 0, 1819, 1822, 1, 0, 0, 0, 1820, 1818,
1, 0, 0, 0, 1820, 1821, 1, 0, 0, 0, 1821, 135, 1, 0, 0, 0, 1822, 1820,
1, 0, 0, 0, 1823, 1824, 5, 109, 0, 0, 1824, 1825, 5, 40, 0, 0, 1825, 1830,
3, 140, 70, 0, 1826, 1827, 5, 5, 0, 0, 1827, 1829, 3, 140, 70, 0, 1828,
1826, 1, 0, 0, 0, 1829, 1832, 1, 0, 0, 0, 1830, 1828, 1, 0, 0, 0, 1830,
1831, 1, 0, 0, 0, 1831, 137, 1, 0, 0, 0, 1832, 1830, 1, 0, 0, 0, 1833,
1834, 5, 98, 0, 0, 1834, 1837, 3, 64, 32, 0, 1835, 1836, 7, 18, 0, 0, 1836,
1838, 3, 64, 32, 0, 1837, 1835, 1, 0, 0, 0, 1837, 1838, 1, 0, 0, 0, 1838,
139, 1, 0, 0, 0, 1839, 1842, 3, 64, 32, 0, 1840, 1841, 5, 45, 0, 0, 1841,
1843, 3, 190, 95, 0, 1842, 1840, 1, 0, 0, 0, 1842, 1843, 1, 0, 0, 0, 1843,
1845, 1, 0, 0, 0, 1844, 1846, 3, 142, 71, 0, 1845, 1844, 1, 0, 0, 0, 1845,
1846, 1, 0, 0, 0, 1846, 1849, 1, 0, 0, 0, 1847, 1848, 5, 175, 0, 0, 1848,
1850, 7, 19, 0, 0, 1849, 1847, 1, 0, 0, 0, 1849, 1850, 1, 0, 0, 0, 1850,
141, 1, 0, 0, 0, 1851, 1852, 7, 20, 0, 0, 1852, 143, 1, 0, 0, 0, 1853,
1854, 3, 64, 32, 0, 1854, 1855, 5, 155, 0, 0, 1855, 1864, 1, 0, 0, 0, 1856,
1857, 3, 64, 32, 0, 1857, 1858, 5, 158, 0, 0, 1858, 1864, 1, 0, 0, 0, 1859,
1860, 5, 157, 0, 0, 1860, 1864, 5, 127, 0, 0, 1861, 1862, 5, 156, 0, 0,
1862, 1864, 5, 155, 0, 0, 1863, 1853, 1, 0, 0, 0, 1863, 1856, 1, 0, 0,
0, 1863, 1859, 1, 0, 0, 0, 1863, 1861, 1, 0, 0, 0, 1864, 145, 1, 0, 0,
0, 1865, 1866, 3, 64, 32, 0, 1866, 1867, 5, 155, 0, 0, 1867, 1876, 1, 0,
0, 0, 1868, 1869, 3, 64, 32, 0, 1869, 1870, 5, 158, 0, 0, 1870, 1876, 1,
0, 0, 0, 1871, 1872, 5, 157, 0, 0, 1872, 1876, 5, 127, 0, 0, 1873, 1874,
5, 156, 0, 0, 1874, 1876, 5, 158, 0, 0, 1875, 1865, 1, 0, 0, 0, 1875, 1868,
1, 0, 0, 0, 1875, 1871, 1, 0, 0, 0, 1875, 1873, 1, 0, 0, 0, 1876, 147,
1, 0, 0, 0, 1877, 1878, 3, 64, 32, 0, 1878, 1879, 5, 155, 0, 0, 1879, 1885,
1, 0, 0, 0, 1880, 1881, 5, 156, 0, 0, 1881, 1885, 5, 155, 0, 0, 1882, 1883,
5, 157, 0, 0, 1883, 1885, 5, 127, 0, 0, 1884, 1877, 1, 0, 0, 0, 1884, 1880,
1, 0, 0, 0, 1884, 1882, 1, 0, 0, 0, 1885, 149, 1, 0, 0, 0, 1886, 1887,
7, 21, 0, 0, 1887, 1888, 5, 3, 0, 0, 1888, 1889, 3, 64, 32, 0, 1889, 1890,
5, 4, 0, 0, 1890, 1891, 5, 152, 0, 0, 1891, 1893, 5, 3, 0, 0, 1892, 1894,
3, 156, 78, 0, 1893, 1892, 1, 0, 0, 0, 1893, 1894, 1, 0, 0, 0, 1894, 1895,
1, 0, 0, 0, 1895, 1897, 3, 160, 80, 0, 1896, 1898, 3, 126, 63, 0, 1897,
1896, 1, 0, 0, 0, 1897, 1898, 1, 0, 0, 0, 1898, 1899, 1, 0, 0, 0, 1899,
1900, 5, 4, 0, 0, 1900, 1972, 1, 0, 0, 0, 1901, 1902, 7, 22, 0, 0, 1902,
1903, 5, 3, 0, 0, 1903, 1904, 5, 4, 0, 0, 1904, 1905, 5, 152, 0, 0, 1905,
1907, 5, 3, 0, 0, 1906, 1908, 3, 156, 78, 0, 1907, 1906, 1, 0, 0, 0, 1907,
1908, 1, 0, 0, 0, 1908, 1910, 1, 0, 0, 0, 1909, 1911, 3, 158, 79, 0, 1910,
1909, 1, 0, 0, 0, 1910, 1911, 1, 0, 0, 0, 1911, 1912, 1, 0, 0, 0, 1912,
1972, 5, 4, 0, 0, 1913, 1914, 7, 23, 0, 0, 1914, 1915, 5, 3, 0, 0, 1915,
1916, 5, 4, 0, 0, 1916, 1917, 5, 152, 0, 0, 1917, 1919, 5, 3, 0, 0, 1918,
1920, 3, 156, 78, 0, 1919, 1918, 1, 0, 0, 0, 1919, 1920, 1, 0, 0, 0, 1920,
1921, 1, 0, 0, 0, 1921, 1922, 3, 160, 80, 0, 1922, 1923, 5, 4, 0, 0, 1923,
1972, 1, 0, 0, 0, 1924, 1925, 7, 24, 0, 0, 1925, 1926, 5, 3, 0, 0, 1926,
1928, 3, 64, 32, 0, 1927, 1929, 3, 152, 76, 0, 1928, 1927, 1, 0, 0, 0,
1928, 1929, 1, 0, 0, 0, 1929, 1931, 1, 0, 0, 0, 1930, 1932, 3, 154, 77,
0, 1931, 1930, 1, 0, 0, 0, 1931, 1932, 1, 0, 0, 0, 1932, 1933, 1, 0, 0,
0, 1933, 1934, 5, 4, 0, 0, 1934, 1935, 5, 152, 0, 0, 1935, 1937, 5, 3,
0, 0, 1936, 1938, 3, 156, 78, 0, 1937, 1936, 1, 0, 0, 0, 1937, 1938, 1,
0, 0, 0, 1938, 1939, 1, 0, 0, 0, 1939, 1940, 3, 160, 80, 0, 1940, 1941,
5, 4, 0, 0, 1941, 1972, 1, 0, 0, 0, 1942, 1943, 5, 164, 0, 0, 1943, 1944,
5, 3, 0, 0, 1944, 1945, 3, 64, 32, 0, 1945, 1946, 5, 5, 0, 0, 1946, 1947,
3, 34, 17, 0, 1947, 1948, 5, 4, 0, 0, 1948, 1949, 5, 152, 0, 0, 1949, 1951,
5, 3, 0, 0, 1950, 1952, 3, 156, 78, 0, 1951, 1950, 1, 0, 0, 0, 1951, 1952,
1, 0, 0, 0, 1952, 1953, 1, 0, 0, 0, 1953, 1955, 3, 160, 80, 0, 1954, 1956,
3, 126, 63, 0, 1955, 1954, 1, 0, 0, 0, 1955, 1956, 1, 0, 0, 0, 1956, 1957,
1, 0, 0, 0, 1957, 1958, 5, 4, 0, 0, 1958, 1972, 1, 0, 0, 0, 1959, 1960,
5, 165, 0, 0, 1960, 1961, 5, 3, 0, 0, 1961, 1962, 3, 64, 32, 0, 1962, 1963,
5, 4, 0, 0, 1963, 1964, 5, 152, 0, 0, 1964, 1966, 5, 3, 0, 0, 1965, 1967,
3, 156, 78, 0, 1966, 1965, 1, 0, 0, 0, 1966, 1967, 1, 0, 0, 0, 1967, 1968,
1, 0, 0, 0, 1968, 1969, 3, 160, 80, 0, 1969, 1970, 5, 4, 0, 0, 1970, 1972,
1, 0, 0, 0, 1971, 1886, 1, 0, 0, 0, 1971, 1901, 1, 0, 0, 0, 1971, 1913,
1, 0, 0, 0, 1971, 1924, 1, 0, 0, 0, 1971, 1942, 1, 0, 0, 0, 1971, 1959,
1, 0, 0, 0, 1972, 151, 1, 0, 0, 0, 1973, 1974, 5, 5, 0, 0, 1974, 1975,
3, 34, 17, 0, 1975, 153, 1, 0, 0, 0, 1976, 1977, 5, 5, 0, 0, 1977, 1978,
3, 34, 17, 0, 1978, 155, 1, 0, 0, 0, 1979, 1980, 5, 153, 0, 0, 1980, 1982,
5, 40, 0, 0, 1981, 1983, 3, 64, 32, 0, 1982, 1981, 1, 0, 0, 0, 1983, 1984,
1, 0, 0, 0, 1984, 1982, 1, 0, 0, 0, 1984, 1985, 1, 0, 0, 0, 1985, 157,
1, 0, 0, 0, 1986, 1987, 5, 109, 0, 0, 1987, 1989, 5, 40, 0, 0, 1988, 1990,
3, 64, 32, 0, 1989, 1988, 1, 0, 0, 0, 1990, 1991, 1, 0, 0, 0, 1991, 1989,
1, 0, 0, 0, 1991, 1992, 1, 0, 0, 0, 1992, 159, 1, 0, 0, 0, 1993, 1994,
5, 109, 0, 0, 1994, 1995, 5, 40, 0, 0, 1995, 1996, 3, 162, 81, 0, 1996,
161, 1, 0, 0, 0, 1997, 1999, 3, 64, 32, 0, 1998, 2000, 3, 142, 71, 0, 1999,
1998, 1, 0, 0, 0, 1999, 2000, 1, 0, 0, 0, 2000, 2008, 1, 0, 0, 0, 2001,
2002, 5, 5, 0, 0, 2002, 2004, 3, 64, 32, 0, 2003, 2005, 3, 142, 71, 0,
2004, 2003, 1, 0, 0, 0, 2004, 2005, 1, 0, 0, 0, 2005, 2007, 1, 0, 0, 0,
2006, 2001, 1, 0, 0, 0, 2007, 2010, 1, 0, 0, 0, 2008, 2006, 1, 0, 0, 0,
2008, 2009, 1, 0, 0, 0, 2009, 163, 1, 0, 0, 0, 2010, 2008, 1, 0, 0, 0,
2011, 2012, 3, 82, 41, 0, 2012, 165, 1, 0, 0, 0, 2013, 2014, 3, 82, 41,
0, 2014, 167, 1, 0, 0, 0, 2015, 2016, 7, 25, 0, 0, 2016, 169, 1, 0, 0,
0, 2017, 2018, 5, 188, 0, 0, 2018, 171, 1, 0, 0, 0, 2019, 2022, 3, 64,
32, 0, 2020, 2022, 3, 28, 14, 0, 2021, 2019, 1, 0, 0, 0, 2021, 2020, 1,
0, 0, 0, 2022, 173, 1, 0, 0, 0, 2023, 2024, 7, 26, 0, 0, 2024, 175, 1,
0, 0, 0, 2025, 2026, 7, 27, 0, 0, 2026, 177, 1, 0, 0, 0, 2027, 2028, 3,
224, 112, 0, 2028, 179, 1, 0, 0, 0, 2029, 2030, 3, 224, 112, 0, 2030, 181,
1, 0, 0, 0, 2031, 2032, 3, 224, 112, 0, 2032, 183, 1, 0, 0, 0, 2033, 2034,
3, 224, 112, 0, 2034, 185, 1, 0, 0, 0, 2035, 2036, 3, 224, 112, 0, 2036,
187, 1, 0, 0, 0, 2037, 2038, 3, 224, 112, 0, 2038, 189, 1, 0, 0, 0, 2039,
2040, 3, 224, 112, 0, 2040, 191, 1, 0, 0, 0, 2041, 2042, 3, 224, 112, 0,
2042, 193, 1, 0, 0, 0, 2043, 2044, 3, 224, 112, 0, 2044, 195, 1, 0, 0,
0, 2045, 2046, 3, 224, 112, 0, 2046, 197, 1, 0, 0, 0, 2047, 2048, 3, 224,
112, 0, 2048, 199, 1, 0, 0, 0, 2049, 2050, 3, 224, 112, 0, 2050, 201, 1,
0, 0, 0, 2051, 2052, 3, 224, 112, 0, 2052, 203, 1, 0, 0, 0, 2053, 2054,
3, 224, 112, 0, 2054, 205, 1, 0, 0, 0, 2055, 2056, 3, 224, 112, 0, 2056,
207, 1, 0, 0, 0, 2057, 2058, 3, 224, 112, 0, 2058, 209, 1, 0, 0, 0, 2059,
2060, 3, 224, 112, 0, 2060, 211, 1, 0, 0, 0, 2061, 2062, 3, 224, 112, 0,
2062, 213, 1, 0, 0, 0, 2063, 2064, 3, 224, 112, 0, 2064, 215, 1, 0, 0,
0, 2065, 2066, 3, 224, 112, 0, 2066, 217, 1, 0, 0, 0, 2067, 2068, 3, 224,
112, 0, 2068, 219, 1, 0, 0, 0, 2069, 2070, 3, 224, 112, 0, 2070, 221, 1,
0, 0, 0, 2071, 2072, 3, 224, 112, 0, 2072, 223, 1, 0, 0, 0, 2073, 2081,
5, 185, 0, 0, 2074, 2081, 3, 176, 88, 0, 2075, 2081, 5, 188, 0, 0, 2076,
2077, 5, 3, 0, 0, 2077, 2078, 3, 224, 112, 0, 2078, 2079, 5, 4, 0, 0, 2079,
2081, 1, 0, 0, 0, 2080, 2073, 1, 0, 0, 0, 2080, 2074, 1, 0, 0, 0, 2080,
2075, 1, 0, 0, 0, 2080, 2076, 1, 0, 0, 0, 2081, 225, 1, 0, 0, 0, 297, 229,
237, 244, 249, 255, 261, 263, 289, 296, 303, 309, 313, 318, 321, 328, 331,
335, 343, 347, 349, 353, 357, 361, 364, 371, 377, 383, 388, 399, 405, 409,
413, 416, 420, 426, 431, 440, 447, 453, 457, 461, 466, 472, 484, 488, 493,
496, 499, 504, 507, 521, 528, 535, 537, 540, 546, 551, 559, 564, 579, 585,
595, 600, 610, 614, 616, 620, 625, 627, 635, 641, 646, 653, 664, 667, 669,
676, 680, 687, 693, 699, 705, 710, 719, 724, 735, 740, 751, 756, 760, 776,
786, 791, 799, 811, 816, 824, 831, 834, 837, 844, 847, 850, 853, 857, 865,
870, 880, 885, 894, 901, 905, 909, 912, 920, 933, 936, 944, 953, 957, 962,
992, 1004, 1009, 1021, 1027, 1034, 1038, 1048, 1051, 1057, 1063, 1072,
1075, 1079, 1081, 1083, 1092, 1099, 1106, 1112, 1117, 1125, 1130, 1139,
1150, 1157, 1161, 1164, 1168, 1171, 1179, 1190, 1196, 1198, 1206, 1213,
1220, 1225, 1227, 1233, 1242, 1247, 1254, 1258, 1260, 1263, 1271, 1275,
1278, 1284, 1288, 1293, 1300, 1309, 1313, 1315, 1319, 1328, 1333, 1335,
1348, 1351, 1360, 1371, 1378, 1381, 1386, 1390, 1393, 1396, 1401, 1405,
1410, 1413, 1416, 1421, 1425, 1428, 1435, 1440, 1449, 1454, 1457, 1465,
1469, 1477, 1480, 1482, 1491, 1494, 1496, 1500, 1504, 1508, 1511, 1522,
1527, 1531, 1535, 1538, 1543, 1554, 1558, 1560, 1564, 1567, 1574, 1579,
1590, 1596, 1601, 1607, 1614, 1621, 1626, 1629, 1632, 1635, 1640, 1645,
1652, 1656, 1660, 1670, 1679, 1682, 1691, 1695, 1703, 1712, 1715, 1724,
1727, 1730, 1733, 1743, 1752, 1761, 1765, 1772, 1779, 1783, 1787, 1796,
1800, 1804, 1809, 1813, 1820, 1830, 1837, 1842, 1845, 1849, 1863, 1875,
1884, 1893, 1897, 1907, 1910, 1919, 1928, 1931, 1937, 1951, 1955, 1966,
1971, 1984, 1991, 1999, 2004, 2008, 2021, 2080,
}
deserializer := antlr.NewATNDeserializer(nil)
staticData.atn = deserializer.Deserialize(staticData.serializedATN)
atn := staticData.atn
staticData.decisionToDFA = make([]*antlr.DFA, len(atn.DecisionToState))
decisionToDFA := staticData.decisionToDFA
for index, state := range atn.DecisionToState {
decisionToDFA[index] = antlr.NewDFA(state, index)
}
}
// ParserInit initializes any static state used to implement Parser. By default the
// static state used to implement the parser is lazily initialized during the first call to
// NewParser(). You can call this function if you wish to initialize the static state ahead
// of time.
func ParserInit() {
staticData := &ParserParserStaticData
staticData.once.Do(parserParserInit)
}
// NewParser produces a new parser instance for the optional input antlr.TokenStream.
func NewParser(input antlr.TokenStream) *Parser {
ParserInit()
this := new(Parser)
this.BaseParser = antlr.NewBaseParser(input)
staticData := &ParserParserStaticData
this.Interpreter = antlr.NewParserATNSimulator(this, staticData.atn, staticData.decisionToDFA, staticData.PredictionContextCache)
this.RuleNames = staticData.RuleNames
this.LiteralNames = staticData.LiteralNames
this.SymbolicNames = staticData.SymbolicNames
this.GrammarFileName = "Parser.g4"
return this
}
// Parser tokens.
const (
ParserEOF = antlr.TokenEOF
ParserSCOL = 1
ParserDOT = 2
ParserOPEN_PAR = 3
ParserCLOSE_PAR = 4
ParserCOMMA = 5
ParserASSIGN = 6
ParserSTAR = 7
ParserPLUS = 8
ParserMINUS = 9
ParserTILDE = 10
ParserPIPE2 = 11
ParserDIV = 12
ParserMOD = 13
ParserLT2 = 14
ParserGT2 = 15
ParserAMP = 16
ParserPIPE = 17
ParserLT = 18
ParserLT_EQ = 19
ParserGT = 20
ParserGT_EQ = 21
ParserEQ = 22
ParserNOT_EQ1 = 23
ParserNOT_EQ2 = 24
ParserABORT_ = 25
ParserACTION_ = 26
ParserADD_ = 27
ParserAFTER_ = 28
ParserALL_ = 29
ParserALTER_ = 30
ParserANALYZE_ = 31
ParserAND_ = 32
ParserAS_ = 33
ParserASC_ = 34
ParserATTACH_ = 35
ParserAUTOINCREMENT_ = 36
ParserBEFORE_ = 37
ParserBEGIN_ = 38
ParserBETWEEN_ = 39
ParserBY_ = 40
ParserCASCADE_ = 41
ParserCASE_ = 42
ParserCAST_ = 43
ParserCHECK_ = 44
ParserCOLLATE_ = 45
ParserCOLUMN_ = 46
ParserCOMMIT_ = 47
ParserCONFLICT_ = 48
ParserCONSTRAINT_ = 49
ParserCREATE_ = 50
ParserCROSS_ = 51
ParserCURRENT_DATE_ = 52
ParserCURRENT_TIME_ = 53
ParserCURRENT_TIMESTAMP_ = 54
ParserDATABASE_ = 55
ParserDEFAULT_ = 56
ParserDEFERRABLE_ = 57
ParserDEFERRED_ = 58
ParserDELETE_ = 59
ParserDESC_ = 60
ParserDETACH_ = 61
ParserDISTINCT_ = 62
ParserDROP_ = 63
ParserEACH_ = 64
ParserELSE_ = 65
ParserEND_ = 66
ParserESCAPE_ = 67
ParserEXCEPT_ = 68
ParserEXCLUSIVE_ = 69
ParserEXISTS_ = 70
ParserEXPLAIN_ = 71
ParserFAIL_ = 72
ParserFOR_ = 73
ParserFOREIGN_ = 74
ParserFROM_ = 75
ParserFULL_ = 76
ParserGLOB_ = 77
ParserGROUP_ = 78
ParserHAVING_ = 79
ParserIF_ = 80
ParserIGNORE_ = 81
ParserIMMEDIATE_ = 82
ParserIN_ = 83
ParserINDEX_ = 84
ParserINDEXED_ = 85
ParserINITIALLY_ = 86
ParserINNER_ = 87
ParserINSERT_ = 88
ParserINSTEAD_ = 89
ParserINTERSECT_ = 90
ParserINTO_ = 91
ParserIS_ = 92
ParserISNULL_ = 93
ParserJOIN_ = 94
ParserKEY_ = 95
ParserLEFT_ = 96
ParserLIKE_ = 97
ParserLIMIT_ = 98
ParserMATCH_ = 99
ParserNATURAL_ = 100
ParserNO_ = 101
ParserNOT_ = 102
ParserNOTNULL_ = 103
ParserNULL_ = 104
ParserOF_ = 105
ParserOFFSET_ = 106
ParserON_ = 107
ParserOR_ = 108
ParserORDER_ = 109
ParserOUTER_ = 110
ParserPLAN_ = 111
ParserPRAGMA_ = 112
ParserPRIMARY_ = 113
ParserQUERY_ = 114
ParserRAISE_ = 115
ParserRECURSIVE_ = 116
ParserREFERENCES_ = 117
ParserREGEXP_ = 118
ParserREINDEX_ = 119
ParserRELEASE_ = 120
ParserRENAME_ = 121
ParserREPLACE_ = 122
ParserRESTRICT_ = 123
ParserRETURNING_ = 124
ParserRIGHT_ = 125
ParserROLLBACK_ = 126
ParserROW_ = 127
ParserROWS_ = 128
ParserSAVEPOINT_ = 129
ParserSELECT_ = 130
ParserSET_ = 131
ParserTABLE_ = 132
ParserTEMP_ = 133
ParserTEMPORARY_ = 134
ParserTHEN_ = 135
ParserTO_ = 136
ParserTRANSACTION_ = 137
ParserTRIGGER_ = 138
ParserUNION_ = 139
ParserUNIQUE_ = 140
ParserUPDATE_ = 141
ParserUSING_ = 142
ParserVACUUM_ = 143
ParserVALUES_ = 144
ParserVIEW_ = 145
ParserVIRTUAL_ = 146
ParserWHEN_ = 147
ParserWHERE_ = 148
ParserWITH_ = 149
ParserWITHOUT_ = 150
ParserFIRST_VALUE_ = 151
ParserOVER_ = 152
ParserPARTITION_ = 153
ParserRANGE_ = 154
ParserPRECEDING_ = 155
ParserUNBOUNDED_ = 156
ParserCURRENT_ = 157
ParserFOLLOWING_ = 158
ParserCUME_DIST_ = 159
ParserDENSE_RANK_ = 160
ParserLAG_ = 161
ParserLAST_VALUE_ = 162
ParserLEAD_ = 163
ParserNTH_VALUE_ = 164
ParserNTILE_ = 165
ParserPERCENT_RANK_ = 166
ParserRANK_ = 167
ParserROW_NUMBER_ = 168
ParserGENERATED_ = 169
ParserALWAYS_ = 170
ParserSTORED_ = 171
ParserTRUE_ = 172
ParserFALSE_ = 173
ParserWINDOW_ = 174
ParserNULLS_ = 175
ParserFIRST_ = 176
ParserLAST_ = 177
ParserFILTER_ = 178
ParserGROUPS_ = 179
ParserEXCLUDE_ = 180
ParserTIES_ = 181
ParserOTHERS_ = 182
ParserDO_ = 183
ParserNOTHING_ = 184
ParserIDENTIFIER = 185
ParserNUMERIC_LITERAL = 186
ParserBIND_PARAMETER = 187
ParserSTRING_LITERAL = 188
ParserBLOB_LITERAL = 189
ParserSINGLE_LINE_COMMENT = 190
ParserMULTILINE_COMMENT = 191
ParserSPACES = 192
ParserUNEXPECTED_CHAR = 193
)
// Parser rules.
const (
ParserRULE_parse = 0
ParserRULE_sql_stmt_list = 1
ParserRULE_sql_stmt = 2
ParserRULE_alter_table_stmt = 3
ParserRULE_analyze_stmt = 4
ParserRULE_attach_stmt = 5
ParserRULE_begin_stmt = 6
ParserRULE_commit_stmt = 7
ParserRULE_rollback_stmt = 8
ParserRULE_savepoint_stmt = 9
ParserRULE_release_stmt = 10
ParserRULE_create_index_stmt = 11
ParserRULE_indexed_column = 12
ParserRULE_create_table_stmt = 13
ParserRULE_column_def = 14
ParserRULE_type_name = 15
ParserRULE_column_constraint = 16
ParserRULE_signed_number = 17
ParserRULE_table_constraint = 18
ParserRULE_foreign_key_clause = 19
ParserRULE_conflict_clause = 20
ParserRULE_create_trigger_stmt = 21
ParserRULE_create_view_stmt = 22
ParserRULE_create_virtual_table_stmt = 23
ParserRULE_with_clause = 24
ParserRULE_cte_table_name = 25
ParserRULE_recursive_cte = 26
ParserRULE_common_table_expression = 27
ParserRULE_delete_stmt = 28
ParserRULE_delete_stmt_limited = 29
ParserRULE_detach_stmt = 30
ParserRULE_drop_stmt = 31
ParserRULE_expr = 32
ParserRULE_raise_function = 33
ParserRULE_literal_value = 34
ParserRULE_insert_stmt = 35
ParserRULE_returning_clause = 36
ParserRULE_upsert_clause = 37
ParserRULE_pragma_stmt = 38
ParserRULE_pragma_value = 39
ParserRULE_reindex_stmt = 40
ParserRULE_select_stmt = 41
ParserRULE_join_clause = 42
ParserRULE_select_core = 43
ParserRULE_factored_select_stmt = 44
ParserRULE_simple_select_stmt = 45
ParserRULE_compound_select_stmt = 46
ParserRULE_table_or_subquery = 47
ParserRULE_result_column = 48
ParserRULE_join_operator = 49
ParserRULE_join_constraint = 50
ParserRULE_compound_operator = 51
ParserRULE_update_stmt = 52
ParserRULE_assignment_list = 53
ParserRULE_assignment = 54
ParserRULE_column_name_list = 55
ParserRULE_update_stmt_limited = 56
ParserRULE_qualified_table_name = 57
ParserRULE_vacuum_stmt = 58
ParserRULE_filter_clause = 59
ParserRULE_window_defn = 60
ParserRULE_over_clause = 61
ParserRULE_frame_spec = 62
ParserRULE_frame_clause = 63
ParserRULE_simple_function_invocation = 64
ParserRULE_aggregate_function_invocation = 65
ParserRULE_window_function_invocation = 66
ParserRULE_common_table_stmt = 67
ParserRULE_order_by_stmt = 68
ParserRULE_limit_stmt = 69
ParserRULE_ordering_term = 70
ParserRULE_asc_desc = 71
ParserRULE_frame_left = 72
ParserRULE_frame_right = 73
ParserRULE_frame_single = 74
ParserRULE_window_function = 75
ParserRULE_offset = 76
ParserRULE_default_value = 77
ParserRULE_partition_by = 78
ParserRULE_order_by_expr = 79
ParserRULE_order_by_expr_asc_desc = 80
ParserRULE_expr_asc_desc = 81
ParserRULE_initial_select = 82
ParserRULE_recursive_select = 83
ParserRULE_unary_operator = 84
ParserRULE_error_message = 85
ParserRULE_module_argument = 86
ParserRULE_column_alias = 87
ParserRULE_keyword = 88
ParserRULE_name = 89
ParserRULE_function_name = 90
ParserRULE_schema_name = 91
ParserRULE_table_name = 92
ParserRULE_table_or_index_name = 93
ParserRULE_column_name = 94
ParserRULE_collation_name = 95
ParserRULE_foreign_table = 96
ParserRULE_index_name = 97
ParserRULE_trigger_name = 98
ParserRULE_view_name = 99
ParserRULE_module_name = 100
ParserRULE_pragma_name = 101
ParserRULE_savepoint_name = 102
ParserRULE_table_alias = 103
ParserRULE_transaction_name = 104
ParserRULE_window_name = 105
ParserRULE_alias = 106
ParserRULE_filename = 107
ParserRULE_base_window_name = 108
ParserRULE_simple_func = 109
ParserRULE_aggregate_func = 110
ParserRULE_table_function_name = 111
ParserRULE_any_name = 112
)
// IParseContext is an interface to support dynamic dispatch.
type IParseContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
EOF() antlr.TerminalNode
AllSql_stmt_list() []ISql_stmt_listContext
Sql_stmt_list(i int) ISql_stmt_listContext
// IsParseContext differentiates from other interfaces.
IsParseContext()
}
type ParseContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyParseContext() *ParseContext {
var p = new(ParseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_parse
return p
}
func InitEmptyParseContext(p *ParseContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_parse
}
func (*ParseContext) IsParseContext() {}
func NewParseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ParseContext {
var p = new(ParseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_parse
return p
}
func (s *ParseContext) GetParser() antlr.Parser { return s.parser }
func (s *ParseContext) EOF() antlr.TerminalNode {
return s.GetToken(ParserEOF, 0)
}
func (s *ParseContext) AllSql_stmt_list() []ISql_stmt_listContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ISql_stmt_listContext); ok {
len++
}
}
tst := make([]ISql_stmt_listContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ISql_stmt_listContext); ok {
tst[i] = t.(ISql_stmt_listContext)
i++
}
}
return tst
}
func (s *ParseContext) Sql_stmt_list(i int) ISql_stmt_listContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISql_stmt_listContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ISql_stmt_listContext)
}
func (s *ParseContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ParseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ParseContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterParse(s)
}
}
func (s *ParseContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitParse(s)
}
}
func (s *ParseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitParse(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Parse() (localctx IParseContext) {
localctx = NewParseContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 0, ParserRULE_parse)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(229)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for ((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&-6339801325483589630) != 0) || ((int64((_la-66)) & ^0x3f) == 0 && ((int64(1)<<(_la-66))&-7971300971697405919) != 0) || ((int64((_la-130)) & ^0x3f) == 0 && ((int64(1)<<(_la-130))&550913) != 0) {
{
p.SetState(226)
p.Sql_stmt_list()
}
p.SetState(231)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(232)
p.Match(ParserEOF)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ISql_stmt_listContext is an interface to support dynamic dispatch.
type ISql_stmt_listContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
AllSql_stmt() []ISql_stmtContext
Sql_stmt(i int) ISql_stmtContext
AllSCOL() []antlr.TerminalNode
SCOL(i int) antlr.TerminalNode
// IsSql_stmt_listContext differentiates from other interfaces.
IsSql_stmt_listContext()
}
type Sql_stmt_listContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptySql_stmt_listContext() *Sql_stmt_listContext {
var p = new(Sql_stmt_listContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_sql_stmt_list
return p
}
func InitEmptySql_stmt_listContext(p *Sql_stmt_listContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_sql_stmt_list
}
func (*Sql_stmt_listContext) IsSql_stmt_listContext() {}
func NewSql_stmt_listContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Sql_stmt_listContext {
var p = new(Sql_stmt_listContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_sql_stmt_list
return p
}
func (s *Sql_stmt_listContext) GetParser() antlr.Parser { return s.parser }
func (s *Sql_stmt_listContext) AllSql_stmt() []ISql_stmtContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ISql_stmtContext); ok {
len++
}
}
tst := make([]ISql_stmtContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ISql_stmtContext); ok {
tst[i] = t.(ISql_stmtContext)
i++
}
}
return tst
}
func (s *Sql_stmt_listContext) Sql_stmt(i int) ISql_stmtContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISql_stmtContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ISql_stmtContext)
}
func (s *Sql_stmt_listContext) AllSCOL() []antlr.TerminalNode {
return s.GetTokens(ParserSCOL)
}
func (s *Sql_stmt_listContext) SCOL(i int) antlr.TerminalNode {
return s.GetToken(ParserSCOL, i)
}
func (s *Sql_stmt_listContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Sql_stmt_listContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Sql_stmt_listContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterSql_stmt_list(s)
}
}
func (s *Sql_stmt_listContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitSql_stmt_list(s)
}
}
func (s *Sql_stmt_listContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitSql_stmt_list(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Sql_stmt_list() (localctx ISql_stmt_listContext) {
localctx = NewSql_stmt_listContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 2, ParserRULE_sql_stmt_list)
var _la int
var _alt int
p.EnterOuterAlt(localctx, 1)
p.SetState(237)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserSCOL {
{
p.SetState(234)
p.Match(ParserSCOL)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(239)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(240)
p.Sql_stmt()
}
p.SetState(249)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 3, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
for _alt != 2 && _alt != antlr.ATNInvalidAltNumber {
if _alt == 1 {
p.SetState(242)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for ok := true; ok; ok = _la == ParserSCOL {
{
p.SetState(241)
p.Match(ParserSCOL)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(244)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(246)
p.Sql_stmt()
}
}
p.SetState(251)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 3, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
}
p.SetState(255)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 4, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
for _alt != 2 && _alt != antlr.ATNInvalidAltNumber {
if _alt == 1 {
{
p.SetState(252)
p.Match(ParserSCOL)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
p.SetState(257)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 4, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ISql_stmtContext is an interface to support dynamic dispatch.
type ISql_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Alter_table_stmt() IAlter_table_stmtContext
Analyze_stmt() IAnalyze_stmtContext
Attach_stmt() IAttach_stmtContext
Begin_stmt() IBegin_stmtContext
Commit_stmt() ICommit_stmtContext
Create_index_stmt() ICreate_index_stmtContext
Create_table_stmt() ICreate_table_stmtContext
Create_trigger_stmt() ICreate_trigger_stmtContext
Create_view_stmt() ICreate_view_stmtContext
Create_virtual_table_stmt() ICreate_virtual_table_stmtContext
Delete_stmt() IDelete_stmtContext
Delete_stmt_limited() IDelete_stmt_limitedContext
Detach_stmt() IDetach_stmtContext
Drop_stmt() IDrop_stmtContext
Insert_stmt() IInsert_stmtContext
Pragma_stmt() IPragma_stmtContext
Reindex_stmt() IReindex_stmtContext
Release_stmt() IRelease_stmtContext
Rollback_stmt() IRollback_stmtContext
Savepoint_stmt() ISavepoint_stmtContext
Select_stmt() ISelect_stmtContext
Update_stmt() IUpdate_stmtContext
Update_stmt_limited() IUpdate_stmt_limitedContext
Vacuum_stmt() IVacuum_stmtContext
EXPLAIN_() antlr.TerminalNode
QUERY_() antlr.TerminalNode
PLAN_() antlr.TerminalNode
// IsSql_stmtContext differentiates from other interfaces.
IsSql_stmtContext()
}
type Sql_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptySql_stmtContext() *Sql_stmtContext {
var p = new(Sql_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_sql_stmt
return p
}
func InitEmptySql_stmtContext(p *Sql_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_sql_stmt
}
func (*Sql_stmtContext) IsSql_stmtContext() {}
func NewSql_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Sql_stmtContext {
var p = new(Sql_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_sql_stmt
return p
}
func (s *Sql_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Sql_stmtContext) Alter_table_stmt() IAlter_table_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAlter_table_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAlter_table_stmtContext)
}
func (s *Sql_stmtContext) Analyze_stmt() IAnalyze_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAnalyze_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAnalyze_stmtContext)
}
func (s *Sql_stmtContext) Attach_stmt() IAttach_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAttach_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAttach_stmtContext)
}
func (s *Sql_stmtContext) Begin_stmt() IBegin_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IBegin_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IBegin_stmtContext)
}
func (s *Sql_stmtContext) Commit_stmt() ICommit_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICommit_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICommit_stmtContext)
}
func (s *Sql_stmtContext) Create_index_stmt() ICreate_index_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICreate_index_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICreate_index_stmtContext)
}
func (s *Sql_stmtContext) Create_table_stmt() ICreate_table_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICreate_table_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICreate_table_stmtContext)
}
func (s *Sql_stmtContext) Create_trigger_stmt() ICreate_trigger_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICreate_trigger_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICreate_trigger_stmtContext)
}
func (s *Sql_stmtContext) Create_view_stmt() ICreate_view_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICreate_view_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICreate_view_stmtContext)
}
func (s *Sql_stmtContext) Create_virtual_table_stmt() ICreate_virtual_table_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICreate_virtual_table_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICreate_virtual_table_stmtContext)
}
func (s *Sql_stmtContext) Delete_stmt() IDelete_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IDelete_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IDelete_stmtContext)
}
func (s *Sql_stmtContext) Delete_stmt_limited() IDelete_stmt_limitedContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IDelete_stmt_limitedContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IDelete_stmt_limitedContext)
}
func (s *Sql_stmtContext) Detach_stmt() IDetach_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IDetach_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IDetach_stmtContext)
}
func (s *Sql_stmtContext) Drop_stmt() IDrop_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IDrop_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IDrop_stmtContext)
}
func (s *Sql_stmtContext) Insert_stmt() IInsert_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IInsert_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IInsert_stmtContext)
}
func (s *Sql_stmtContext) Pragma_stmt() IPragma_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IPragma_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IPragma_stmtContext)
}
func (s *Sql_stmtContext) Reindex_stmt() IReindex_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IReindex_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IReindex_stmtContext)
}
func (s *Sql_stmtContext) Release_stmt() IRelease_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IRelease_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IRelease_stmtContext)
}
func (s *Sql_stmtContext) Rollback_stmt() IRollback_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IRollback_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IRollback_stmtContext)
}
func (s *Sql_stmtContext) Savepoint_stmt() ISavepoint_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISavepoint_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISavepoint_stmtContext)
}
func (s *Sql_stmtContext) Select_stmt() ISelect_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *Sql_stmtContext) Update_stmt() IUpdate_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IUpdate_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IUpdate_stmtContext)
}
func (s *Sql_stmtContext) Update_stmt_limited() IUpdate_stmt_limitedContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IUpdate_stmt_limitedContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IUpdate_stmt_limitedContext)
}
func (s *Sql_stmtContext) Vacuum_stmt() IVacuum_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IVacuum_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IVacuum_stmtContext)
}
func (s *Sql_stmtContext) EXPLAIN_() antlr.TerminalNode {
return s.GetToken(ParserEXPLAIN_, 0)
}
func (s *Sql_stmtContext) QUERY_() antlr.TerminalNode {
return s.GetToken(ParserQUERY_, 0)
}
func (s *Sql_stmtContext) PLAN_() antlr.TerminalNode {
return s.GetToken(ParserPLAN_, 0)
}
func (s *Sql_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Sql_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Sql_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterSql_stmt(s)
}
}
func (s *Sql_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitSql_stmt(s)
}
}
func (s *Sql_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitSql_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Sql_stmt() (localctx ISql_stmtContext) {
localctx = NewSql_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 4, ParserRULE_sql_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(263)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserEXPLAIN_ {
{
p.SetState(258)
p.Match(ParserEXPLAIN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(261)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserQUERY_ {
{
p.SetState(259)
p.Match(ParserQUERY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(260)
p.Match(ParserPLAN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
}
p.SetState(289)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 7, p.GetParserRuleContext()) {
case 1:
{
p.SetState(265)
p.Alter_table_stmt()
}
case 2:
{
p.SetState(266)
p.Analyze_stmt()
}
case 3:
{
p.SetState(267)
p.Attach_stmt()
}
case 4:
{
p.SetState(268)
p.Begin_stmt()
}
case 5:
{
p.SetState(269)
p.Commit_stmt()
}
case 6:
{
p.SetState(270)
p.Create_index_stmt()
}
case 7:
{
p.SetState(271)
p.Create_table_stmt()
}
case 8:
{
p.SetState(272)
p.Create_trigger_stmt()
}
case 9:
{
p.SetState(273)
p.Create_view_stmt()
}
case 10:
{
p.SetState(274)
p.Create_virtual_table_stmt()
}
case 11:
{
p.SetState(275)
p.Delete_stmt()
}
case 12:
{
p.SetState(276)
p.Delete_stmt_limited()
}
case 13:
{
p.SetState(277)
p.Detach_stmt()
}
case 14:
{
p.SetState(278)
p.Drop_stmt()
}
case 15:
{
p.SetState(279)
p.Insert_stmt()
}
case 16:
{
p.SetState(280)
p.Pragma_stmt()
}
case 17:
{
p.SetState(281)
p.Reindex_stmt()
}
case 18:
{
p.SetState(282)
p.Release_stmt()
}
case 19:
{
p.SetState(283)
p.Rollback_stmt()
}
case 20:
{
p.SetState(284)
p.Savepoint_stmt()
}
case 21:
{
p.SetState(285)
p.Select_stmt()
}
case 22:
{
p.SetState(286)
p.Update_stmt()
}
case 23:
{
p.SetState(287)
p.Update_stmt_limited()
}
case 24:
{
p.SetState(288)
p.Vacuum_stmt()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IAlter_table_stmtContext is an interface to support dynamic dispatch.
type IAlter_table_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetNew_table_name returns the new_table_name rule contexts.
GetNew_table_name() ITable_nameContext
// GetOld_column_name returns the old_column_name rule contexts.
GetOld_column_name() IColumn_nameContext
// GetNew_column_name returns the new_column_name rule contexts.
GetNew_column_name() IColumn_nameContext
// SetNew_table_name sets the new_table_name rule contexts.
SetNew_table_name(ITable_nameContext)
// SetOld_column_name sets the old_column_name rule contexts.
SetOld_column_name(IColumn_nameContext)
// SetNew_column_name sets the new_column_name rule contexts.
SetNew_column_name(IColumn_nameContext)
// Getter signatures
ALTER_() antlr.TerminalNode
TABLE_() antlr.TerminalNode
AllTable_name() []ITable_nameContext
Table_name(i int) ITable_nameContext
RENAME_() antlr.TerminalNode
ADD_() antlr.TerminalNode
Column_def() IColumn_defContext
DROP_() antlr.TerminalNode
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
TO_() antlr.TerminalNode
COLUMN_() antlr.TerminalNode
// IsAlter_table_stmtContext differentiates from other interfaces.
IsAlter_table_stmtContext()
}
type Alter_table_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
new_table_name ITable_nameContext
old_column_name IColumn_nameContext
new_column_name IColumn_nameContext
}
func NewEmptyAlter_table_stmtContext() *Alter_table_stmtContext {
var p = new(Alter_table_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_alter_table_stmt
return p
}
func InitEmptyAlter_table_stmtContext(p *Alter_table_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_alter_table_stmt
}
func (*Alter_table_stmtContext) IsAlter_table_stmtContext() {}
func NewAlter_table_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Alter_table_stmtContext {
var p = new(Alter_table_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_alter_table_stmt
return p
}
func (s *Alter_table_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Alter_table_stmtContext) GetNew_table_name() ITable_nameContext { return s.new_table_name }
func (s *Alter_table_stmtContext) GetOld_column_name() IColumn_nameContext { return s.old_column_name }
func (s *Alter_table_stmtContext) GetNew_column_name() IColumn_nameContext { return s.new_column_name }
func (s *Alter_table_stmtContext) SetNew_table_name(v ITable_nameContext) { s.new_table_name = v }
func (s *Alter_table_stmtContext) SetOld_column_name(v IColumn_nameContext) { s.old_column_name = v }
func (s *Alter_table_stmtContext) SetNew_column_name(v IColumn_nameContext) { s.new_column_name = v }
func (s *Alter_table_stmtContext) ALTER_() antlr.TerminalNode {
return s.GetToken(ParserALTER_, 0)
}
func (s *Alter_table_stmtContext) TABLE_() antlr.TerminalNode {
return s.GetToken(ParserTABLE_, 0)
}
func (s *Alter_table_stmtContext) AllTable_name() []ITable_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ITable_nameContext); ok {
len++
}
}
tst := make([]ITable_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ITable_nameContext); ok {
tst[i] = t.(ITable_nameContext)
i++
}
}
return tst
}
func (s *Alter_table_stmtContext) Table_name(i int) ITable_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Alter_table_stmtContext) RENAME_() antlr.TerminalNode {
return s.GetToken(ParserRENAME_, 0)
}
func (s *Alter_table_stmtContext) ADD_() antlr.TerminalNode {
return s.GetToken(ParserADD_, 0)
}
func (s *Alter_table_stmtContext) Column_def() IColumn_defContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_defContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IColumn_defContext)
}
func (s *Alter_table_stmtContext) DROP_() antlr.TerminalNode {
return s.GetToken(ParserDROP_, 0)
}
func (s *Alter_table_stmtContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Alter_table_stmtContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Alter_table_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Alter_table_stmtContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Alter_table_stmtContext) TO_() antlr.TerminalNode {
return s.GetToken(ParserTO_, 0)
}
func (s *Alter_table_stmtContext) COLUMN_() antlr.TerminalNode {
return s.GetToken(ParserCOLUMN_, 0)
}
func (s *Alter_table_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Alter_table_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Alter_table_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterAlter_table_stmt(s)
}
}
func (s *Alter_table_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitAlter_table_stmt(s)
}
}
func (s *Alter_table_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitAlter_table_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Alter_table_stmt() (localctx IAlter_table_stmtContext) {
localctx = NewAlter_table_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 6, ParserRULE_alter_table_stmt)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(291)
p.Match(ParserALTER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(292)
p.Match(ParserTABLE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(296)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 8, p.GetParserRuleContext()) == 1 {
{
p.SetState(293)
p.Schema_name()
}
{
p.SetState(294)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(298)
p.Table_name()
}
p.SetState(321)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserRENAME_:
{
p.SetState(299)
p.Match(ParserRENAME_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(309)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 10, p.GetParserRuleContext()) {
case 1:
{
p.SetState(300)
p.Match(ParserTO_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(301)
var _x = p.Table_name()
localctx.(*Alter_table_stmtContext).new_table_name = _x
}
case 2:
p.SetState(303)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 9, p.GetParserRuleContext()) == 1 {
{
p.SetState(302)
p.Match(ParserCOLUMN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(305)
var _x = p.Column_name()
localctx.(*Alter_table_stmtContext).old_column_name = _x
}
{
p.SetState(306)
p.Match(ParserTO_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(307)
var _x = p.Column_name()
localctx.(*Alter_table_stmtContext).new_column_name = _x
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
case ParserADD_:
{
p.SetState(311)
p.Match(ParserADD_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(313)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 11, p.GetParserRuleContext()) == 1 {
{
p.SetState(312)
p.Match(ParserCOLUMN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(315)
p.Column_def()
}
case ParserDROP_:
{
p.SetState(316)
p.Match(ParserDROP_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(318)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 12, p.GetParserRuleContext()) == 1 {
{
p.SetState(317)
p.Match(ParserCOLUMN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(320)
p.Column_name()
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IAnalyze_stmtContext is an interface to support dynamic dispatch.
type IAnalyze_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ANALYZE_() antlr.TerminalNode
Schema_name() ISchema_nameContext
Table_or_index_name() ITable_or_index_nameContext
DOT() antlr.TerminalNode
// IsAnalyze_stmtContext differentiates from other interfaces.
IsAnalyze_stmtContext()
}
type Analyze_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyAnalyze_stmtContext() *Analyze_stmtContext {
var p = new(Analyze_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_analyze_stmt
return p
}
func InitEmptyAnalyze_stmtContext(p *Analyze_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_analyze_stmt
}
func (*Analyze_stmtContext) IsAnalyze_stmtContext() {}
func NewAnalyze_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Analyze_stmtContext {
var p = new(Analyze_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_analyze_stmt
return p
}
func (s *Analyze_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Analyze_stmtContext) ANALYZE_() antlr.TerminalNode {
return s.GetToken(ParserANALYZE_, 0)
}
func (s *Analyze_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Analyze_stmtContext) Table_or_index_name() ITable_or_index_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_or_index_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_or_index_nameContext)
}
func (s *Analyze_stmtContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Analyze_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Analyze_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Analyze_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterAnalyze_stmt(s)
}
}
func (s *Analyze_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitAnalyze_stmt(s)
}
}
func (s *Analyze_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitAnalyze_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Analyze_stmt() (localctx IAnalyze_stmtContext) {
localctx = NewAnalyze_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 8, ParserRULE_analyze_stmt)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(323)
p.Match(ParserANALYZE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(331)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 15, p.GetParserRuleContext()) == 1 {
{
p.SetState(324)
p.Schema_name()
}
} else if p.HasError() { // JIM
goto errorExit
} else if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 15, p.GetParserRuleContext()) == 2 {
p.SetState(328)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 14, p.GetParserRuleContext()) == 1 {
{
p.SetState(325)
p.Schema_name()
}
{
p.SetState(326)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(330)
p.Table_or_index_name()
}
} else if p.HasError() { // JIM
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IAttach_stmtContext is an interface to support dynamic dispatch.
type IAttach_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ATTACH_() antlr.TerminalNode
Expr() IExprContext
AS_() antlr.TerminalNode
Schema_name() ISchema_nameContext
DATABASE_() antlr.TerminalNode
// IsAttach_stmtContext differentiates from other interfaces.
IsAttach_stmtContext()
}
type Attach_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyAttach_stmtContext() *Attach_stmtContext {
var p = new(Attach_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_attach_stmt
return p
}
func InitEmptyAttach_stmtContext(p *Attach_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_attach_stmt
}
func (*Attach_stmtContext) IsAttach_stmtContext() {}
func NewAttach_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Attach_stmtContext {
var p = new(Attach_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_attach_stmt
return p
}
func (s *Attach_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Attach_stmtContext) ATTACH_() antlr.TerminalNode {
return s.GetToken(ParserATTACH_, 0)
}
func (s *Attach_stmtContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Attach_stmtContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *Attach_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Attach_stmtContext) DATABASE_() antlr.TerminalNode {
return s.GetToken(ParserDATABASE_, 0)
}
func (s *Attach_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Attach_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Attach_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterAttach_stmt(s)
}
}
func (s *Attach_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitAttach_stmt(s)
}
}
func (s *Attach_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitAttach_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Attach_stmt() (localctx IAttach_stmtContext) {
localctx = NewAttach_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 10, ParserRULE_attach_stmt)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(333)
p.Match(ParserATTACH_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(335)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 16, p.GetParserRuleContext()) == 1 {
{
p.SetState(334)
p.Match(ParserDATABASE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(337)
p.expr(0)
}
{
p.SetState(338)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(339)
p.Schema_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IBegin_stmtContext is an interface to support dynamic dispatch.
type IBegin_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
BEGIN_() antlr.TerminalNode
TRANSACTION_() antlr.TerminalNode
DEFERRED_() antlr.TerminalNode
IMMEDIATE_() antlr.TerminalNode
EXCLUSIVE_() antlr.TerminalNode
Transaction_name() ITransaction_nameContext
// IsBegin_stmtContext differentiates from other interfaces.
IsBegin_stmtContext()
}
type Begin_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyBegin_stmtContext() *Begin_stmtContext {
var p = new(Begin_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_begin_stmt
return p
}
func InitEmptyBegin_stmtContext(p *Begin_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_begin_stmt
}
func (*Begin_stmtContext) IsBegin_stmtContext() {}
func NewBegin_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Begin_stmtContext {
var p = new(Begin_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_begin_stmt
return p
}
func (s *Begin_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Begin_stmtContext) BEGIN_() antlr.TerminalNode {
return s.GetToken(ParserBEGIN_, 0)
}
func (s *Begin_stmtContext) TRANSACTION_() antlr.TerminalNode {
return s.GetToken(ParserTRANSACTION_, 0)
}
func (s *Begin_stmtContext) DEFERRED_() antlr.TerminalNode {
return s.GetToken(ParserDEFERRED_, 0)
}
func (s *Begin_stmtContext) IMMEDIATE_() antlr.TerminalNode {
return s.GetToken(ParserIMMEDIATE_, 0)
}
func (s *Begin_stmtContext) EXCLUSIVE_() antlr.TerminalNode {
return s.GetToken(ParserEXCLUSIVE_, 0)
}
func (s *Begin_stmtContext) Transaction_name() ITransaction_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITransaction_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITransaction_nameContext)
}
func (s *Begin_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Begin_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Begin_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterBegin_stmt(s)
}
}
func (s *Begin_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitBegin_stmt(s)
}
}
func (s *Begin_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitBegin_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Begin_stmt() (localctx IBegin_stmtContext) {
localctx = NewBegin_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 12, ParserRULE_begin_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(341)
p.Match(ParserBEGIN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(343)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if (int64((_la-58)) & ^0x3f) == 0 && ((int64(1)<<(_la-58))&16779265) != 0 {
{
p.SetState(342)
_la = p.GetTokenStream().LA(1)
if !((int64((_la-58)) & ^0x3f) == 0 && ((int64(1)<<(_la-58))&16779265) != 0) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
}
p.SetState(349)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserTRANSACTION_ {
{
p.SetState(345)
p.Match(ParserTRANSACTION_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(347)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 18, p.GetParserRuleContext()) == 1 {
{
p.SetState(346)
p.Transaction_name()
}
} else if p.HasError() { // JIM
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICommit_stmtContext is an interface to support dynamic dispatch.
type ICommit_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
COMMIT_() antlr.TerminalNode
END_() antlr.TerminalNode
TRANSACTION_() antlr.TerminalNode
// IsCommit_stmtContext differentiates from other interfaces.
IsCommit_stmtContext()
}
type Commit_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyCommit_stmtContext() *Commit_stmtContext {
var p = new(Commit_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_commit_stmt
return p
}
func InitEmptyCommit_stmtContext(p *Commit_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_commit_stmt
}
func (*Commit_stmtContext) IsCommit_stmtContext() {}
func NewCommit_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Commit_stmtContext {
var p = new(Commit_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_commit_stmt
return p
}
func (s *Commit_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Commit_stmtContext) COMMIT_() antlr.TerminalNode {
return s.GetToken(ParserCOMMIT_, 0)
}
func (s *Commit_stmtContext) END_() antlr.TerminalNode {
return s.GetToken(ParserEND_, 0)
}
func (s *Commit_stmtContext) TRANSACTION_() antlr.TerminalNode {
return s.GetToken(ParserTRANSACTION_, 0)
}
func (s *Commit_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Commit_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Commit_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCommit_stmt(s)
}
}
func (s *Commit_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCommit_stmt(s)
}
}
func (s *Commit_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCommit_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Commit_stmt() (localctx ICommit_stmtContext) {
localctx = NewCommit_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 14, ParserRULE_commit_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(351)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserCOMMIT_ || _la == ParserEND_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
p.SetState(353)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserTRANSACTION_ {
{
p.SetState(352)
p.Match(ParserTRANSACTION_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IRollback_stmtContext is an interface to support dynamic dispatch.
type IRollback_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ROLLBACK_() antlr.TerminalNode
TRANSACTION_() antlr.TerminalNode
TO_() antlr.TerminalNode
Savepoint_name() ISavepoint_nameContext
SAVEPOINT_() antlr.TerminalNode
// IsRollback_stmtContext differentiates from other interfaces.
IsRollback_stmtContext()
}
type Rollback_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyRollback_stmtContext() *Rollback_stmtContext {
var p = new(Rollback_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_rollback_stmt
return p
}
func InitEmptyRollback_stmtContext(p *Rollback_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_rollback_stmt
}
func (*Rollback_stmtContext) IsRollback_stmtContext() {}
func NewRollback_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Rollback_stmtContext {
var p = new(Rollback_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_rollback_stmt
return p
}
func (s *Rollback_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Rollback_stmtContext) ROLLBACK_() antlr.TerminalNode {
return s.GetToken(ParserROLLBACK_, 0)
}
func (s *Rollback_stmtContext) TRANSACTION_() antlr.TerminalNode {
return s.GetToken(ParserTRANSACTION_, 0)
}
func (s *Rollback_stmtContext) TO_() antlr.TerminalNode {
return s.GetToken(ParserTO_, 0)
}
func (s *Rollback_stmtContext) Savepoint_name() ISavepoint_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISavepoint_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISavepoint_nameContext)
}
func (s *Rollback_stmtContext) SAVEPOINT_() antlr.TerminalNode {
return s.GetToken(ParserSAVEPOINT_, 0)
}
func (s *Rollback_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Rollback_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Rollback_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterRollback_stmt(s)
}
}
func (s *Rollback_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitRollback_stmt(s)
}
}
func (s *Rollback_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitRollback_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Rollback_stmt() (localctx IRollback_stmtContext) {
localctx = NewRollback_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 16, ParserRULE_rollback_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(355)
p.Match(ParserROLLBACK_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(357)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserTRANSACTION_ {
{
p.SetState(356)
p.Match(ParserTRANSACTION_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
p.SetState(364)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserTO_ {
{
p.SetState(359)
p.Match(ParserTO_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(361)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 22, p.GetParserRuleContext()) == 1 {
{
p.SetState(360)
p.Match(ParserSAVEPOINT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(363)
p.Savepoint_name()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ISavepoint_stmtContext is an interface to support dynamic dispatch.
type ISavepoint_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
SAVEPOINT_() antlr.TerminalNode
Savepoint_name() ISavepoint_nameContext
// IsSavepoint_stmtContext differentiates from other interfaces.
IsSavepoint_stmtContext()
}
type Savepoint_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptySavepoint_stmtContext() *Savepoint_stmtContext {
var p = new(Savepoint_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_savepoint_stmt
return p
}
func InitEmptySavepoint_stmtContext(p *Savepoint_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_savepoint_stmt
}
func (*Savepoint_stmtContext) IsSavepoint_stmtContext() {}
func NewSavepoint_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Savepoint_stmtContext {
var p = new(Savepoint_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_savepoint_stmt
return p
}
func (s *Savepoint_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Savepoint_stmtContext) SAVEPOINT_() antlr.TerminalNode {
return s.GetToken(ParserSAVEPOINT_, 0)
}
func (s *Savepoint_stmtContext) Savepoint_name() ISavepoint_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISavepoint_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISavepoint_nameContext)
}
func (s *Savepoint_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Savepoint_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Savepoint_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterSavepoint_stmt(s)
}
}
func (s *Savepoint_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitSavepoint_stmt(s)
}
}
func (s *Savepoint_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitSavepoint_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Savepoint_stmt() (localctx ISavepoint_stmtContext) {
localctx = NewSavepoint_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 18, ParserRULE_savepoint_stmt)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(366)
p.Match(ParserSAVEPOINT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(367)
p.Savepoint_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IRelease_stmtContext is an interface to support dynamic dispatch.
type IRelease_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
RELEASE_() antlr.TerminalNode
Savepoint_name() ISavepoint_nameContext
SAVEPOINT_() antlr.TerminalNode
// IsRelease_stmtContext differentiates from other interfaces.
IsRelease_stmtContext()
}
type Release_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyRelease_stmtContext() *Release_stmtContext {
var p = new(Release_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_release_stmt
return p
}
func InitEmptyRelease_stmtContext(p *Release_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_release_stmt
}
func (*Release_stmtContext) IsRelease_stmtContext() {}
func NewRelease_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Release_stmtContext {
var p = new(Release_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_release_stmt
return p
}
func (s *Release_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Release_stmtContext) RELEASE_() antlr.TerminalNode {
return s.GetToken(ParserRELEASE_, 0)
}
func (s *Release_stmtContext) Savepoint_name() ISavepoint_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISavepoint_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISavepoint_nameContext)
}
func (s *Release_stmtContext) SAVEPOINT_() antlr.TerminalNode {
return s.GetToken(ParserSAVEPOINT_, 0)
}
func (s *Release_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Release_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Release_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterRelease_stmt(s)
}
}
func (s *Release_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitRelease_stmt(s)
}
}
func (s *Release_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitRelease_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Release_stmt() (localctx IRelease_stmtContext) {
localctx = NewRelease_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 20, ParserRULE_release_stmt)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(369)
p.Match(ParserRELEASE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(371)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 24, p.GetParserRuleContext()) == 1 {
{
p.SetState(370)
p.Match(ParserSAVEPOINT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(373)
p.Savepoint_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICreate_index_stmtContext is an interface to support dynamic dispatch.
type ICreate_index_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
CREATE_() antlr.TerminalNode
INDEX_() antlr.TerminalNode
Index_name() IIndex_nameContext
ON_() antlr.TerminalNode
Table_name() ITable_nameContext
OPEN_PAR() antlr.TerminalNode
AllIndexed_column() []IIndexed_columnContext
Indexed_column(i int) IIndexed_columnContext
CLOSE_PAR() antlr.TerminalNode
UNIQUE_() antlr.TerminalNode
IF_() antlr.TerminalNode
NOT_() antlr.TerminalNode
EXISTS_() antlr.TerminalNode
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
WHERE_() antlr.TerminalNode
Expr() IExprContext
// IsCreate_index_stmtContext differentiates from other interfaces.
IsCreate_index_stmtContext()
}
type Create_index_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyCreate_index_stmtContext() *Create_index_stmtContext {
var p = new(Create_index_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_create_index_stmt
return p
}
func InitEmptyCreate_index_stmtContext(p *Create_index_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_create_index_stmt
}
func (*Create_index_stmtContext) IsCreate_index_stmtContext() {}
func NewCreate_index_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Create_index_stmtContext {
var p = new(Create_index_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_create_index_stmt
return p
}
func (s *Create_index_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Create_index_stmtContext) CREATE_() antlr.TerminalNode {
return s.GetToken(ParserCREATE_, 0)
}
func (s *Create_index_stmtContext) INDEX_() antlr.TerminalNode {
return s.GetToken(ParserINDEX_, 0)
}
func (s *Create_index_stmtContext) Index_name() IIndex_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IIndex_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IIndex_nameContext)
}
func (s *Create_index_stmtContext) ON_() antlr.TerminalNode {
return s.GetToken(ParserON_, 0)
}
func (s *Create_index_stmtContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Create_index_stmtContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Create_index_stmtContext) AllIndexed_column() []IIndexed_columnContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IIndexed_columnContext); ok {
len++
}
}
tst := make([]IIndexed_columnContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IIndexed_columnContext); ok {
tst[i] = t.(IIndexed_columnContext)
i++
}
}
return tst
}
func (s *Create_index_stmtContext) Indexed_column(i int) IIndexed_columnContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IIndexed_columnContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IIndexed_columnContext)
}
func (s *Create_index_stmtContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Create_index_stmtContext) UNIQUE_() antlr.TerminalNode {
return s.GetToken(ParserUNIQUE_, 0)
}
func (s *Create_index_stmtContext) IF_() antlr.TerminalNode {
return s.GetToken(ParserIF_, 0)
}
func (s *Create_index_stmtContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *Create_index_stmtContext) EXISTS_() antlr.TerminalNode {
return s.GetToken(ParserEXISTS_, 0)
}
func (s *Create_index_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Create_index_stmtContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Create_index_stmtContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Create_index_stmtContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Create_index_stmtContext) WHERE_() antlr.TerminalNode {
return s.GetToken(ParserWHERE_, 0)
}
func (s *Create_index_stmtContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Create_index_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Create_index_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Create_index_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCreate_index_stmt(s)
}
}
func (s *Create_index_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCreate_index_stmt(s)
}
}
func (s *Create_index_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCreate_index_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Create_index_stmt() (localctx ICreate_index_stmtContext) {
localctx = NewCreate_index_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 22, ParserRULE_create_index_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(375)
p.Match(ParserCREATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(377)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserUNIQUE_ {
{
p.SetState(376)
p.Match(ParserUNIQUE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(379)
p.Match(ParserINDEX_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(383)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 26, p.GetParserRuleContext()) == 1 {
{
p.SetState(380)
p.Match(ParserIF_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(381)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(382)
p.Match(ParserEXISTS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(388)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 27, p.GetParserRuleContext()) == 1 {
{
p.SetState(385)
p.Schema_name()
}
{
p.SetState(386)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(390)
p.Index_name()
}
{
p.SetState(391)
p.Match(ParserON_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(392)
p.Table_name()
}
{
p.SetState(393)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(394)
p.Indexed_column()
}
p.SetState(399)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(395)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(396)
p.Indexed_column()
}
p.SetState(401)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(402)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(405)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWHERE_ {
{
p.SetState(403)
p.Match(ParserWHERE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(404)
p.expr(0)
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IIndexed_columnContext is an interface to support dynamic dispatch.
type IIndexed_columnContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Column_name() IColumn_nameContext
Expr() IExprContext
COLLATE_() antlr.TerminalNode
Collation_name() ICollation_nameContext
Asc_desc() IAsc_descContext
// IsIndexed_columnContext differentiates from other interfaces.
IsIndexed_columnContext()
}
type Indexed_columnContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyIndexed_columnContext() *Indexed_columnContext {
var p = new(Indexed_columnContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_indexed_column
return p
}
func InitEmptyIndexed_columnContext(p *Indexed_columnContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_indexed_column
}
func (*Indexed_columnContext) IsIndexed_columnContext() {}
func NewIndexed_columnContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Indexed_columnContext {
var p = new(Indexed_columnContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_indexed_column
return p
}
func (s *Indexed_columnContext) GetParser() antlr.Parser { return s.parser }
func (s *Indexed_columnContext) Column_name() IColumn_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Indexed_columnContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Indexed_columnContext) COLLATE_() antlr.TerminalNode {
return s.GetToken(ParserCOLLATE_, 0)
}
func (s *Indexed_columnContext) Collation_name() ICollation_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICollation_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICollation_nameContext)
}
func (s *Indexed_columnContext) Asc_desc() IAsc_descContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAsc_descContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAsc_descContext)
}
func (s *Indexed_columnContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Indexed_columnContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Indexed_columnContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterIndexed_column(s)
}
}
func (s *Indexed_columnContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitIndexed_column(s)
}
}
func (s *Indexed_columnContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitIndexed_column(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Indexed_column() (localctx IIndexed_columnContext) {
localctx = NewIndexed_columnContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 24, ParserRULE_indexed_column)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(409)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 30, p.GetParserRuleContext()) {
case 1:
{
p.SetState(407)
p.Column_name()
}
case 2:
{
p.SetState(408)
p.expr(0)
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
p.SetState(413)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserCOLLATE_ {
{
p.SetState(411)
p.Match(ParserCOLLATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(412)
p.Collation_name()
}
}
p.SetState(416)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserASC_ || _la == ParserDESC_ {
{
p.SetState(415)
p.Asc_desc()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICreate_table_stmtContext is an interface to support dynamic dispatch.
type ICreate_table_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetRow_ROW_ID returns the row_ROW_ID token.
GetRow_ROW_ID() antlr.Token
// SetRow_ROW_ID sets the row_ROW_ID token.
SetRow_ROW_ID(antlr.Token)
// Getter signatures
CREATE_() antlr.TerminalNode
TABLE_() antlr.TerminalNode
Table_name() ITable_nameContext
OPEN_PAR() antlr.TerminalNode
AllColumn_def() []IColumn_defContext
Column_def(i int) IColumn_defContext
CLOSE_PAR() antlr.TerminalNode
AS_() antlr.TerminalNode
Select_stmt() ISelect_stmtContext
IF_() antlr.TerminalNode
NOT_() antlr.TerminalNode
EXISTS_() antlr.TerminalNode
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
TEMP_() antlr.TerminalNode
TEMPORARY_() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
AllTable_constraint() []ITable_constraintContext
Table_constraint(i int) ITable_constraintContext
WITHOUT_() antlr.TerminalNode
IDENTIFIER() antlr.TerminalNode
// IsCreate_table_stmtContext differentiates from other interfaces.
IsCreate_table_stmtContext()
}
type Create_table_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
row_ROW_ID antlr.Token
}
func NewEmptyCreate_table_stmtContext() *Create_table_stmtContext {
var p = new(Create_table_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_create_table_stmt
return p
}
func InitEmptyCreate_table_stmtContext(p *Create_table_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_create_table_stmt
}
func (*Create_table_stmtContext) IsCreate_table_stmtContext() {}
func NewCreate_table_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Create_table_stmtContext {
var p = new(Create_table_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_create_table_stmt
return p
}
func (s *Create_table_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Create_table_stmtContext) GetRow_ROW_ID() antlr.Token { return s.row_ROW_ID }
func (s *Create_table_stmtContext) SetRow_ROW_ID(v antlr.Token) { s.row_ROW_ID = v }
func (s *Create_table_stmtContext) CREATE_() antlr.TerminalNode {
return s.GetToken(ParserCREATE_, 0)
}
func (s *Create_table_stmtContext) TABLE_() antlr.TerminalNode {
return s.GetToken(ParserTABLE_, 0)
}
func (s *Create_table_stmtContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Create_table_stmtContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Create_table_stmtContext) AllColumn_def() []IColumn_defContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_defContext); ok {
len++
}
}
tst := make([]IColumn_defContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_defContext); ok {
tst[i] = t.(IColumn_defContext)
i++
}
}
return tst
}
func (s *Create_table_stmtContext) Column_def(i int) IColumn_defContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_defContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_defContext)
}
func (s *Create_table_stmtContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Create_table_stmtContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *Create_table_stmtContext) Select_stmt() ISelect_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *Create_table_stmtContext) IF_() antlr.TerminalNode {
return s.GetToken(ParserIF_, 0)
}
func (s *Create_table_stmtContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *Create_table_stmtContext) EXISTS_() antlr.TerminalNode {
return s.GetToken(ParserEXISTS_, 0)
}
func (s *Create_table_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Create_table_stmtContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Create_table_stmtContext) TEMP_() antlr.TerminalNode {
return s.GetToken(ParserTEMP_, 0)
}
func (s *Create_table_stmtContext) TEMPORARY_() antlr.TerminalNode {
return s.GetToken(ParserTEMPORARY_, 0)
}
func (s *Create_table_stmtContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Create_table_stmtContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Create_table_stmtContext) AllTable_constraint() []ITable_constraintContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ITable_constraintContext); ok {
len++
}
}
tst := make([]ITable_constraintContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ITable_constraintContext); ok {
tst[i] = t.(ITable_constraintContext)
i++
}
}
return tst
}
func (s *Create_table_stmtContext) Table_constraint(i int) ITable_constraintContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_constraintContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ITable_constraintContext)
}
func (s *Create_table_stmtContext) WITHOUT_() antlr.TerminalNode {
return s.GetToken(ParserWITHOUT_, 0)
}
func (s *Create_table_stmtContext) IDENTIFIER() antlr.TerminalNode {
return s.GetToken(ParserIDENTIFIER, 0)
}
func (s *Create_table_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Create_table_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Create_table_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCreate_table_stmt(s)
}
}
func (s *Create_table_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCreate_table_stmt(s)
}
}
func (s *Create_table_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCreate_table_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Create_table_stmt() (localctx ICreate_table_stmtContext) {
localctx = NewCreate_table_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 26, ParserRULE_create_table_stmt)
var _la int
var _alt int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(418)
p.Match(ParserCREATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(420)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserTEMP_ || _la == ParserTEMPORARY_ {
{
p.SetState(419)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserTEMP_ || _la == ParserTEMPORARY_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
}
{
p.SetState(422)
p.Match(ParserTABLE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(426)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 34, p.GetParserRuleContext()) == 1 {
{
p.SetState(423)
p.Match(ParserIF_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(424)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(425)
p.Match(ParserEXISTS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(431)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 35, p.GetParserRuleContext()) == 1 {
{
p.SetState(428)
p.Schema_name()
}
{
p.SetState(429)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(433)
p.Table_name()
}
p.SetState(457)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserOPEN_PAR:
{
p.SetState(434)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(435)
p.Column_def()
}
p.SetState(440)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 36, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
for _alt != 1 && _alt != antlr.ATNInvalidAltNumber {
if _alt == 1+1 {
{
p.SetState(436)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(437)
p.Column_def()
}
}
p.SetState(442)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 36, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
}
p.SetState(447)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(443)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(444)
p.Table_constraint()
}
p.SetState(449)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(450)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(453)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWITHOUT_ {
{
p.SetState(451)
p.Match(ParserWITHOUT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(452)
var _m = p.Match(ParserIDENTIFIER)
localctx.(*Create_table_stmtContext).row_ROW_ID = _m
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
case ParserAS_:
{
p.SetState(455)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(456)
p.Select_stmt()
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IColumn_defContext is an interface to support dynamic dispatch.
type IColumn_defContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Column_name() IColumn_nameContext
Type_name() IType_nameContext
AllColumn_constraint() []IColumn_constraintContext
Column_constraint(i int) IColumn_constraintContext
// IsColumn_defContext differentiates from other interfaces.
IsColumn_defContext()
}
type Column_defContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyColumn_defContext() *Column_defContext {
var p = new(Column_defContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_column_def
return p
}
func InitEmptyColumn_defContext(p *Column_defContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_column_def
}
func (*Column_defContext) IsColumn_defContext() {}
func NewColumn_defContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Column_defContext {
var p = new(Column_defContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_column_def
return p
}
func (s *Column_defContext) GetParser() antlr.Parser { return s.parser }
func (s *Column_defContext) Column_name() IColumn_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Column_defContext) Type_name() IType_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IType_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IType_nameContext)
}
func (s *Column_defContext) AllColumn_constraint() []IColumn_constraintContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_constraintContext); ok {
len++
}
}
tst := make([]IColumn_constraintContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_constraintContext); ok {
tst[i] = t.(IColumn_constraintContext)
i++
}
}
return tst
}
func (s *Column_defContext) Column_constraint(i int) IColumn_constraintContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_constraintContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_constraintContext)
}
func (s *Column_defContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Column_defContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Column_defContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterColumn_def(s)
}
}
func (s *Column_defContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitColumn_def(s)
}
}
func (s *Column_defContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitColumn_def(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Column_def() (localctx IColumn_defContext) {
localctx = NewColumn_defContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 28, ParserRULE_column_def)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(459)
p.Column_name()
}
p.SetState(461)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 40, p.GetParserRuleContext()) == 1 {
{
p.SetState(460)
p.Type_name()
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(466)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for ((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&72673329139417088) != 0) || ((int64((_la-102)) & ^0x3f) == 0 && ((int64(1)<<(_la-102))&274877941761) != 0) || _la == ParserGENERATED_ {
{
p.SetState(463)
p.Column_constraint()
}
p.SetState(468)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IType_nameContext is an interface to support dynamic dispatch.
type IType_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
AllName() []INameContext
Name(i int) INameContext
OPEN_PAR() antlr.TerminalNode
AllSigned_number() []ISigned_numberContext
Signed_number(i int) ISigned_numberContext
CLOSE_PAR() antlr.TerminalNode
COMMA() antlr.TerminalNode
// IsType_nameContext differentiates from other interfaces.
IsType_nameContext()
}
type Type_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyType_nameContext() *Type_nameContext {
var p = new(Type_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_type_name
return p
}
func InitEmptyType_nameContext(p *Type_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_type_name
}
func (*Type_nameContext) IsType_nameContext() {}
func NewType_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Type_nameContext {
var p = new(Type_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_type_name
return p
}
func (s *Type_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Type_nameContext) AllName() []INameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(INameContext); ok {
len++
}
}
tst := make([]INameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(INameContext); ok {
tst[i] = t.(INameContext)
i++
}
}
return tst
}
func (s *Type_nameContext) Name(i int) INameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(INameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(INameContext)
}
func (s *Type_nameContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Type_nameContext) AllSigned_number() []ISigned_numberContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ISigned_numberContext); ok {
len++
}
}
tst := make([]ISigned_numberContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ISigned_numberContext); ok {
tst[i] = t.(ISigned_numberContext)
i++
}
}
return tst
}
func (s *Type_nameContext) Signed_number(i int) ISigned_numberContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISigned_numberContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ISigned_numberContext)
}
func (s *Type_nameContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Type_nameContext) COMMA() antlr.TerminalNode {
return s.GetToken(ParserCOMMA, 0)
}
func (s *Type_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Type_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Type_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterType_name(s)
}
}
func (s *Type_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitType_name(s)
}
}
func (s *Type_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitType_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Type_name() (localctx IType_nameContext) {
localctx = NewType_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 30, ParserRULE_type_name)
var _alt int
p.EnterOuterAlt(localctx, 1)
p.SetState(470)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = 1 + 1
for ok := true; ok; ok = _alt != 1 && _alt != antlr.ATNInvalidAltNumber {
switch _alt {
case 1 + 1:
{
p.SetState(469)
p.Name()
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
p.SetState(472)
p.GetErrorHandler().Sync(p)
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 42, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
}
p.SetState(484)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 43, p.GetParserRuleContext()) == 1 {
{
p.SetState(474)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(475)
p.Signed_number()
}
{
p.SetState(476)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
} else if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 43, p.GetParserRuleContext()) == 2 {
{
p.SetState(478)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(479)
p.Signed_number()
}
{
p.SetState(480)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(481)
p.Signed_number()
}
{
p.SetState(482)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IColumn_constraintContext is an interface to support dynamic dispatch.
type IColumn_constraintContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
CHECK_() antlr.TerminalNode
OPEN_PAR() antlr.TerminalNode
Expr() IExprContext
CLOSE_PAR() antlr.TerminalNode
DEFAULT_() antlr.TerminalNode
COLLATE_() antlr.TerminalNode
Collation_name() ICollation_nameContext
Foreign_key_clause() IForeign_key_clauseContext
AS_() antlr.TerminalNode
CONSTRAINT_() antlr.TerminalNode
Name() INameContext
PRIMARY_() antlr.TerminalNode
KEY_() antlr.TerminalNode
NOT_() antlr.TerminalNode
NULL_() antlr.TerminalNode
UNIQUE_() antlr.TerminalNode
Signed_number() ISigned_numberContext
Literal_value() ILiteral_valueContext
Conflict_clause() IConflict_clauseContext
GENERATED_() antlr.TerminalNode
ALWAYS_() antlr.TerminalNode
STORED_() antlr.TerminalNode
VIRTUAL_() antlr.TerminalNode
Asc_desc() IAsc_descContext
AUTOINCREMENT_() antlr.TerminalNode
// IsColumn_constraintContext differentiates from other interfaces.
IsColumn_constraintContext()
}
type Column_constraintContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyColumn_constraintContext() *Column_constraintContext {
var p = new(Column_constraintContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_column_constraint
return p
}
func InitEmptyColumn_constraintContext(p *Column_constraintContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_column_constraint
}
func (*Column_constraintContext) IsColumn_constraintContext() {}
func NewColumn_constraintContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Column_constraintContext {
var p = new(Column_constraintContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_column_constraint
return p
}
func (s *Column_constraintContext) GetParser() antlr.Parser { return s.parser }
func (s *Column_constraintContext) CHECK_() antlr.TerminalNode {
return s.GetToken(ParserCHECK_, 0)
}
func (s *Column_constraintContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Column_constraintContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Column_constraintContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Column_constraintContext) DEFAULT_() antlr.TerminalNode {
return s.GetToken(ParserDEFAULT_, 0)
}
func (s *Column_constraintContext) COLLATE_() antlr.TerminalNode {
return s.GetToken(ParserCOLLATE_, 0)
}
func (s *Column_constraintContext) Collation_name() ICollation_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICollation_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICollation_nameContext)
}
func (s *Column_constraintContext) Foreign_key_clause() IForeign_key_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IForeign_key_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IForeign_key_clauseContext)
}
func (s *Column_constraintContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *Column_constraintContext) CONSTRAINT_() antlr.TerminalNode {
return s.GetToken(ParserCONSTRAINT_, 0)
}
func (s *Column_constraintContext) Name() INameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(INameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(INameContext)
}
func (s *Column_constraintContext) PRIMARY_() antlr.TerminalNode {
return s.GetToken(ParserPRIMARY_, 0)
}
func (s *Column_constraintContext) KEY_() antlr.TerminalNode {
return s.GetToken(ParserKEY_, 0)
}
func (s *Column_constraintContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *Column_constraintContext) NULL_() antlr.TerminalNode {
return s.GetToken(ParserNULL_, 0)
}
func (s *Column_constraintContext) UNIQUE_() antlr.TerminalNode {
return s.GetToken(ParserUNIQUE_, 0)
}
func (s *Column_constraintContext) Signed_number() ISigned_numberContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISigned_numberContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISigned_numberContext)
}
func (s *Column_constraintContext) Literal_value() ILiteral_valueContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ILiteral_valueContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ILiteral_valueContext)
}
func (s *Column_constraintContext) Conflict_clause() IConflict_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IConflict_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IConflict_clauseContext)
}
func (s *Column_constraintContext) GENERATED_() antlr.TerminalNode {
return s.GetToken(ParserGENERATED_, 0)
}
func (s *Column_constraintContext) ALWAYS_() antlr.TerminalNode {
return s.GetToken(ParserALWAYS_, 0)
}
func (s *Column_constraintContext) STORED_() antlr.TerminalNode {
return s.GetToken(ParserSTORED_, 0)
}
func (s *Column_constraintContext) VIRTUAL_() antlr.TerminalNode {
return s.GetToken(ParserVIRTUAL_, 0)
}
func (s *Column_constraintContext) Asc_desc() IAsc_descContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAsc_descContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAsc_descContext)
}
func (s *Column_constraintContext) AUTOINCREMENT_() antlr.TerminalNode {
return s.GetToken(ParserAUTOINCREMENT_, 0)
}
func (s *Column_constraintContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Column_constraintContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Column_constraintContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterColumn_constraint(s)
}
}
func (s *Column_constraintContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitColumn_constraint(s)
}
}
func (s *Column_constraintContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitColumn_constraint(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Column_constraint() (localctx IColumn_constraintContext) {
localctx = NewColumn_constraintContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 32, ParserRULE_column_constraint)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(488)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserCONSTRAINT_ {
{
p.SetState(486)
p.Match(ParserCONSTRAINT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(487)
p.Name()
}
}
p.SetState(537)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserPRIMARY_:
{
p.SetState(490)
p.Match(ParserPRIMARY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(491)
p.Match(ParserKEY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(493)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserASC_ || _la == ParserDESC_ {
{
p.SetState(492)
p.Asc_desc()
}
}
p.SetState(496)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserON_ {
{
p.SetState(495)
p.Conflict_clause()
}
}
p.SetState(499)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserAUTOINCREMENT_ {
{
p.SetState(498)
p.Match(ParserAUTOINCREMENT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
case ParserNOT_, ParserUNIQUE_:
p.SetState(504)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserNOT_:
{
p.SetState(501)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(502)
p.Match(ParserNULL_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserUNIQUE_:
{
p.SetState(503)
p.Match(ParserUNIQUE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
p.SetState(507)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserON_ {
{
p.SetState(506)
p.Conflict_clause()
}
}
case ParserCHECK_:
{
p.SetState(509)
p.Match(ParserCHECK_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(510)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(511)
p.expr(0)
}
{
p.SetState(512)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserDEFAULT_:
{
p.SetState(514)
p.Match(ParserDEFAULT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(521)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 50, p.GetParserRuleContext()) {
case 1:
{
p.SetState(515)
p.Signed_number()
}
case 2:
{
p.SetState(516)
p.Literal_value()
}
case 3:
{
p.SetState(517)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(518)
p.expr(0)
}
{
p.SetState(519)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
case ParserCOLLATE_:
{
p.SetState(523)
p.Match(ParserCOLLATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(524)
p.Collation_name()
}
case ParserREFERENCES_:
{
p.SetState(525)
p.Foreign_key_clause()
}
case ParserAS_, ParserGENERATED_:
p.SetState(528)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserGENERATED_ {
{
p.SetState(526)
p.Match(ParserGENERATED_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(527)
p.Match(ParserALWAYS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(530)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(531)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(532)
p.expr(0)
}
{
p.SetState(533)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(535)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserVIRTUAL_ || _la == ParserSTORED_ {
{
p.SetState(534)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserVIRTUAL_ || _la == ParserSTORED_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ISigned_numberContext is an interface to support dynamic dispatch.
type ISigned_numberContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
NUMERIC_LITERAL() antlr.TerminalNode
PLUS() antlr.TerminalNode
MINUS() antlr.TerminalNode
// IsSigned_numberContext differentiates from other interfaces.
IsSigned_numberContext()
}
type Signed_numberContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptySigned_numberContext() *Signed_numberContext {
var p = new(Signed_numberContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_signed_number
return p
}
func InitEmptySigned_numberContext(p *Signed_numberContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_signed_number
}
func (*Signed_numberContext) IsSigned_numberContext() {}
func NewSigned_numberContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Signed_numberContext {
var p = new(Signed_numberContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_signed_number
return p
}
func (s *Signed_numberContext) GetParser() antlr.Parser { return s.parser }
func (s *Signed_numberContext) NUMERIC_LITERAL() antlr.TerminalNode {
return s.GetToken(ParserNUMERIC_LITERAL, 0)
}
func (s *Signed_numberContext) PLUS() antlr.TerminalNode {
return s.GetToken(ParserPLUS, 0)
}
func (s *Signed_numberContext) MINUS() antlr.TerminalNode {
return s.GetToken(ParserMINUS, 0)
}
func (s *Signed_numberContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Signed_numberContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Signed_numberContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterSigned_number(s)
}
}
func (s *Signed_numberContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitSigned_number(s)
}
}
func (s *Signed_numberContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitSigned_number(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Signed_number() (localctx ISigned_numberContext) {
localctx = NewSigned_numberContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 34, ParserRULE_signed_number)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(540)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserPLUS || _la == ParserMINUS {
{
p.SetState(539)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserPLUS || _la == ParserMINUS) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
}
{
p.SetState(542)
p.Match(ParserNUMERIC_LITERAL)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ITable_constraintContext is an interface to support dynamic dispatch.
type ITable_constraintContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
OPEN_PAR() antlr.TerminalNode
AllIndexed_column() []IIndexed_columnContext
Indexed_column(i int) IIndexed_columnContext
CLOSE_PAR() antlr.TerminalNode
CHECK_() antlr.TerminalNode
Expr() IExprContext
FOREIGN_() antlr.TerminalNode
KEY_() antlr.TerminalNode
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
Foreign_key_clause() IForeign_key_clauseContext
CONSTRAINT_() antlr.TerminalNode
Name() INameContext
PRIMARY_() antlr.TerminalNode
UNIQUE_() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
Conflict_clause() IConflict_clauseContext
// IsTable_constraintContext differentiates from other interfaces.
IsTable_constraintContext()
}
type Table_constraintContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyTable_constraintContext() *Table_constraintContext {
var p = new(Table_constraintContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_constraint
return p
}
func InitEmptyTable_constraintContext(p *Table_constraintContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_constraint
}
func (*Table_constraintContext) IsTable_constraintContext() {}
func NewTable_constraintContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_constraintContext {
var p = new(Table_constraintContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_table_constraint
return p
}
func (s *Table_constraintContext) GetParser() antlr.Parser { return s.parser }
func (s *Table_constraintContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Table_constraintContext) AllIndexed_column() []IIndexed_columnContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IIndexed_columnContext); ok {
len++
}
}
tst := make([]IIndexed_columnContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IIndexed_columnContext); ok {
tst[i] = t.(IIndexed_columnContext)
i++
}
}
return tst
}
func (s *Table_constraintContext) Indexed_column(i int) IIndexed_columnContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IIndexed_columnContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IIndexed_columnContext)
}
func (s *Table_constraintContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Table_constraintContext) CHECK_() antlr.TerminalNode {
return s.GetToken(ParserCHECK_, 0)
}
func (s *Table_constraintContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Table_constraintContext) FOREIGN_() antlr.TerminalNode {
return s.GetToken(ParserFOREIGN_, 0)
}
func (s *Table_constraintContext) KEY_() antlr.TerminalNode {
return s.GetToken(ParserKEY_, 0)
}
func (s *Table_constraintContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Table_constraintContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Table_constraintContext) Foreign_key_clause() IForeign_key_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IForeign_key_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IForeign_key_clauseContext)
}
func (s *Table_constraintContext) CONSTRAINT_() antlr.TerminalNode {
return s.GetToken(ParserCONSTRAINT_, 0)
}
func (s *Table_constraintContext) Name() INameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(INameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(INameContext)
}
func (s *Table_constraintContext) PRIMARY_() antlr.TerminalNode {
return s.GetToken(ParserPRIMARY_, 0)
}
func (s *Table_constraintContext) UNIQUE_() antlr.TerminalNode {
return s.GetToken(ParserUNIQUE_, 0)
}
func (s *Table_constraintContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Table_constraintContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Table_constraintContext) Conflict_clause() IConflict_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IConflict_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IConflict_clauseContext)
}
func (s *Table_constraintContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Table_constraintContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Table_constraintContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterTable_constraint(s)
}
}
func (s *Table_constraintContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitTable_constraint(s)
}
}
func (s *Table_constraintContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitTable_constraint(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Table_constraint() (localctx ITable_constraintContext) {
localctx = NewTable_constraintContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 36, ParserRULE_table_constraint)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(546)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserCONSTRAINT_ {
{
p.SetState(544)
p.Match(ParserCONSTRAINT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(545)
p.Name()
}
}
p.SetState(585)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserPRIMARY_, ParserUNIQUE_:
p.SetState(551)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserPRIMARY_:
{
p.SetState(548)
p.Match(ParserPRIMARY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(549)
p.Match(ParserKEY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserUNIQUE_:
{
p.SetState(550)
p.Match(ParserUNIQUE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
{
p.SetState(553)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(554)
p.Indexed_column()
}
p.SetState(559)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(555)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(556)
p.Indexed_column()
}
p.SetState(561)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(562)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(564)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserON_ {
{
p.SetState(563)
p.Conflict_clause()
}
}
case ParserCHECK_:
{
p.SetState(566)
p.Match(ParserCHECK_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(567)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(568)
p.expr(0)
}
{
p.SetState(569)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserFOREIGN_:
{
p.SetState(571)
p.Match(ParserFOREIGN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(572)
p.Match(ParserKEY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(573)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(574)
p.Column_name()
}
p.SetState(579)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(575)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(576)
p.Column_name()
}
p.SetState(581)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(582)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(583)
p.Foreign_key_clause()
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IForeign_key_clauseContext is an interface to support dynamic dispatch.
type IForeign_key_clauseContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
REFERENCES_() antlr.TerminalNode
Foreign_table() IForeign_tableContext
OPEN_PAR() antlr.TerminalNode
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
CLOSE_PAR() antlr.TerminalNode
AllON_() []antlr.TerminalNode
ON_(i int) antlr.TerminalNode
AllMATCH_() []antlr.TerminalNode
MATCH_(i int) antlr.TerminalNode
AllName() []INameContext
Name(i int) INameContext
DEFERRABLE_() antlr.TerminalNode
AllDELETE_() []antlr.TerminalNode
DELETE_(i int) antlr.TerminalNode
AllUPDATE_() []antlr.TerminalNode
UPDATE_(i int) antlr.TerminalNode
AllSET_() []antlr.TerminalNode
SET_(i int) antlr.TerminalNode
AllCASCADE_() []antlr.TerminalNode
CASCADE_(i int) antlr.TerminalNode
AllRESTRICT_() []antlr.TerminalNode
RESTRICT_(i int) antlr.TerminalNode
AllNO_() []antlr.TerminalNode
NO_(i int) antlr.TerminalNode
AllACTION_() []antlr.TerminalNode
ACTION_(i int) antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
AllNULL_() []antlr.TerminalNode
NULL_(i int) antlr.TerminalNode
AllDEFAULT_() []antlr.TerminalNode
DEFAULT_(i int) antlr.TerminalNode
NOT_() antlr.TerminalNode
INITIALLY_() antlr.TerminalNode
DEFERRED_() antlr.TerminalNode
IMMEDIATE_() antlr.TerminalNode
// IsForeign_key_clauseContext differentiates from other interfaces.
IsForeign_key_clauseContext()
}
type Foreign_key_clauseContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyForeign_key_clauseContext() *Foreign_key_clauseContext {
var p = new(Foreign_key_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_foreign_key_clause
return p
}
func InitEmptyForeign_key_clauseContext(p *Foreign_key_clauseContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_foreign_key_clause
}
func (*Foreign_key_clauseContext) IsForeign_key_clauseContext() {}
func NewForeign_key_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Foreign_key_clauseContext {
var p = new(Foreign_key_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_foreign_key_clause
return p
}
func (s *Foreign_key_clauseContext) GetParser() antlr.Parser { return s.parser }
func (s *Foreign_key_clauseContext) REFERENCES_() antlr.TerminalNode {
return s.GetToken(ParserREFERENCES_, 0)
}
func (s *Foreign_key_clauseContext) Foreign_table() IForeign_tableContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IForeign_tableContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IForeign_tableContext)
}
func (s *Foreign_key_clauseContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Foreign_key_clauseContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Foreign_key_clauseContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Foreign_key_clauseContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Foreign_key_clauseContext) AllON_() []antlr.TerminalNode {
return s.GetTokens(ParserON_)
}
func (s *Foreign_key_clauseContext) ON_(i int) antlr.TerminalNode {
return s.GetToken(ParserON_, i)
}
func (s *Foreign_key_clauseContext) AllMATCH_() []antlr.TerminalNode {
return s.GetTokens(ParserMATCH_)
}
func (s *Foreign_key_clauseContext) MATCH_(i int) antlr.TerminalNode {
return s.GetToken(ParserMATCH_, i)
}
func (s *Foreign_key_clauseContext) AllName() []INameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(INameContext); ok {
len++
}
}
tst := make([]INameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(INameContext); ok {
tst[i] = t.(INameContext)
i++
}
}
return tst
}
func (s *Foreign_key_clauseContext) Name(i int) INameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(INameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(INameContext)
}
func (s *Foreign_key_clauseContext) DEFERRABLE_() antlr.TerminalNode {
return s.GetToken(ParserDEFERRABLE_, 0)
}
func (s *Foreign_key_clauseContext) AllDELETE_() []antlr.TerminalNode {
return s.GetTokens(ParserDELETE_)
}
func (s *Foreign_key_clauseContext) DELETE_(i int) antlr.TerminalNode {
return s.GetToken(ParserDELETE_, i)
}
func (s *Foreign_key_clauseContext) AllUPDATE_() []antlr.TerminalNode {
return s.GetTokens(ParserUPDATE_)
}
func (s *Foreign_key_clauseContext) UPDATE_(i int) antlr.TerminalNode {
return s.GetToken(ParserUPDATE_, i)
}
func (s *Foreign_key_clauseContext) AllSET_() []antlr.TerminalNode {
return s.GetTokens(ParserSET_)
}
func (s *Foreign_key_clauseContext) SET_(i int) antlr.TerminalNode {
return s.GetToken(ParserSET_, i)
}
func (s *Foreign_key_clauseContext) AllCASCADE_() []antlr.TerminalNode {
return s.GetTokens(ParserCASCADE_)
}
func (s *Foreign_key_clauseContext) CASCADE_(i int) antlr.TerminalNode {
return s.GetToken(ParserCASCADE_, i)
}
func (s *Foreign_key_clauseContext) AllRESTRICT_() []antlr.TerminalNode {
return s.GetTokens(ParserRESTRICT_)
}
func (s *Foreign_key_clauseContext) RESTRICT_(i int) antlr.TerminalNode {
return s.GetToken(ParserRESTRICT_, i)
}
func (s *Foreign_key_clauseContext) AllNO_() []antlr.TerminalNode {
return s.GetTokens(ParserNO_)
}
func (s *Foreign_key_clauseContext) NO_(i int) antlr.TerminalNode {
return s.GetToken(ParserNO_, i)
}
func (s *Foreign_key_clauseContext) AllACTION_() []antlr.TerminalNode {
return s.GetTokens(ParserACTION_)
}
func (s *Foreign_key_clauseContext) ACTION_(i int) antlr.TerminalNode {
return s.GetToken(ParserACTION_, i)
}
func (s *Foreign_key_clauseContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Foreign_key_clauseContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Foreign_key_clauseContext) AllNULL_() []antlr.TerminalNode {
return s.GetTokens(ParserNULL_)
}
func (s *Foreign_key_clauseContext) NULL_(i int) antlr.TerminalNode {
return s.GetToken(ParserNULL_, i)
}
func (s *Foreign_key_clauseContext) AllDEFAULT_() []antlr.TerminalNode {
return s.GetTokens(ParserDEFAULT_)
}
func (s *Foreign_key_clauseContext) DEFAULT_(i int) antlr.TerminalNode {
return s.GetToken(ParserDEFAULT_, i)
}
func (s *Foreign_key_clauseContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *Foreign_key_clauseContext) INITIALLY_() antlr.TerminalNode {
return s.GetToken(ParserINITIALLY_, 0)
}
func (s *Foreign_key_clauseContext) DEFERRED_() antlr.TerminalNode {
return s.GetToken(ParserDEFERRED_, 0)
}
func (s *Foreign_key_clauseContext) IMMEDIATE_() antlr.TerminalNode {
return s.GetToken(ParserIMMEDIATE_, 0)
}
func (s *Foreign_key_clauseContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Foreign_key_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Foreign_key_clauseContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterForeign_key_clause(s)
}
}
func (s *Foreign_key_clauseContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitForeign_key_clause(s)
}
}
func (s *Foreign_key_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitForeign_key_clause(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Foreign_key_clause() (localctx IForeign_key_clauseContext) {
localctx = NewForeign_key_clauseContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 38, ParserRULE_foreign_key_clause)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(587)
p.Match(ParserREFERENCES_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(588)
p.Foreign_table()
}
p.SetState(600)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserOPEN_PAR {
{
p.SetState(589)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(590)
p.Column_name()
}
p.SetState(595)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(591)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(592)
p.Column_name()
}
p.SetState(597)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(598)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
p.SetState(616)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserMATCH_ || _la == ParserON_ {
p.SetState(614)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserON_:
{
p.SetState(602)
p.Match(ParserON_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(603)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserDELETE_ || _la == ParserUPDATE_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
p.SetState(610)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserSET_:
{
p.SetState(604)
p.Match(ParserSET_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(605)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserDEFAULT_ || _la == ParserNULL_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
case ParserCASCADE_:
{
p.SetState(606)
p.Match(ParserCASCADE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserRESTRICT_:
{
p.SetState(607)
p.Match(ParserRESTRICT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserNO_:
{
p.SetState(608)
p.Match(ParserNO_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(609)
p.Match(ParserACTION_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
case ParserMATCH_:
{
p.SetState(612)
p.Match(ParserMATCH_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(613)
p.Name()
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
p.SetState(618)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
p.SetState(627)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 68, p.GetParserRuleContext()) == 1 {
p.SetState(620)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserNOT_ {
{
p.SetState(619)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(622)
p.Match(ParserDEFERRABLE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(625)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserINITIALLY_ {
{
p.SetState(623)
p.Match(ParserINITIALLY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(624)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserDEFERRED_ || _la == ParserIMMEDIATE_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
}
} else if p.HasError() { // JIM
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IConflict_clauseContext is an interface to support dynamic dispatch.
type IConflict_clauseContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ON_() antlr.TerminalNode
CONFLICT_() antlr.TerminalNode
ROLLBACK_() antlr.TerminalNode
ABORT_() antlr.TerminalNode
FAIL_() antlr.TerminalNode
IGNORE_() antlr.TerminalNode
REPLACE_() antlr.TerminalNode
// IsConflict_clauseContext differentiates from other interfaces.
IsConflict_clauseContext()
}
type Conflict_clauseContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyConflict_clauseContext() *Conflict_clauseContext {
var p = new(Conflict_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_conflict_clause
return p
}
func InitEmptyConflict_clauseContext(p *Conflict_clauseContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_conflict_clause
}
func (*Conflict_clauseContext) IsConflict_clauseContext() {}
func NewConflict_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Conflict_clauseContext {
var p = new(Conflict_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_conflict_clause
return p
}
func (s *Conflict_clauseContext) GetParser() antlr.Parser { return s.parser }
func (s *Conflict_clauseContext) ON_() antlr.TerminalNode {
return s.GetToken(ParserON_, 0)
}
func (s *Conflict_clauseContext) CONFLICT_() antlr.TerminalNode {
return s.GetToken(ParserCONFLICT_, 0)
}
func (s *Conflict_clauseContext) ROLLBACK_() antlr.TerminalNode {
return s.GetToken(ParserROLLBACK_, 0)
}
func (s *Conflict_clauseContext) ABORT_() antlr.TerminalNode {
return s.GetToken(ParserABORT_, 0)
}
func (s *Conflict_clauseContext) FAIL_() antlr.TerminalNode {
return s.GetToken(ParserFAIL_, 0)
}
func (s *Conflict_clauseContext) IGNORE_() antlr.TerminalNode {
return s.GetToken(ParserIGNORE_, 0)
}
func (s *Conflict_clauseContext) REPLACE_() antlr.TerminalNode {
return s.GetToken(ParserREPLACE_, 0)
}
func (s *Conflict_clauseContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Conflict_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Conflict_clauseContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterConflict_clause(s)
}
}
func (s *Conflict_clauseContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitConflict_clause(s)
}
}
func (s *Conflict_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitConflict_clause(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Conflict_clause() (localctx IConflict_clauseContext) {
localctx = NewConflict_clauseContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 40, ParserRULE_conflict_clause)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(629)
p.Match(ParserON_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(630)
p.Match(ParserCONFLICT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(631)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserABORT_ || ((int64((_la-72)) & ^0x3f) == 0 && ((int64(1)<<(_la-72))&19140298416325121) != 0)) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICreate_trigger_stmtContext is an interface to support dynamic dispatch.
type ICreate_trigger_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
CREATE_() antlr.TerminalNode
TRIGGER_() antlr.TerminalNode
Trigger_name() ITrigger_nameContext
ON_() antlr.TerminalNode
Table_name() ITable_nameContext
BEGIN_() antlr.TerminalNode
END_() antlr.TerminalNode
DELETE_() antlr.TerminalNode
INSERT_() antlr.TerminalNode
UPDATE_() antlr.TerminalNode
IF_() antlr.TerminalNode
NOT_() antlr.TerminalNode
EXISTS_() antlr.TerminalNode
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
BEFORE_() antlr.TerminalNode
AFTER_() antlr.TerminalNode
INSTEAD_() antlr.TerminalNode
AllOF_() []antlr.TerminalNode
OF_(i int) antlr.TerminalNode
FOR_() antlr.TerminalNode
EACH_() antlr.TerminalNode
ROW_() antlr.TerminalNode
WHEN_() antlr.TerminalNode
Expr() IExprContext
AllSCOL() []antlr.TerminalNode
SCOL(i int) antlr.TerminalNode
TEMP_() antlr.TerminalNode
TEMPORARY_() antlr.TerminalNode
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
AllUpdate_stmt() []IUpdate_stmtContext
Update_stmt(i int) IUpdate_stmtContext
AllInsert_stmt() []IInsert_stmtContext
Insert_stmt(i int) IInsert_stmtContext
AllDelete_stmt() []IDelete_stmtContext
Delete_stmt(i int) IDelete_stmtContext
AllSelect_stmt() []ISelect_stmtContext
Select_stmt(i int) ISelect_stmtContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsCreate_trigger_stmtContext differentiates from other interfaces.
IsCreate_trigger_stmtContext()
}
type Create_trigger_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyCreate_trigger_stmtContext() *Create_trigger_stmtContext {
var p = new(Create_trigger_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_create_trigger_stmt
return p
}
func InitEmptyCreate_trigger_stmtContext(p *Create_trigger_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_create_trigger_stmt
}
func (*Create_trigger_stmtContext) IsCreate_trigger_stmtContext() {}
func NewCreate_trigger_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Create_trigger_stmtContext {
var p = new(Create_trigger_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_create_trigger_stmt
return p
}
func (s *Create_trigger_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Create_trigger_stmtContext) CREATE_() antlr.TerminalNode {
return s.GetToken(ParserCREATE_, 0)
}
func (s *Create_trigger_stmtContext) TRIGGER_() antlr.TerminalNode {
return s.GetToken(ParserTRIGGER_, 0)
}
func (s *Create_trigger_stmtContext) Trigger_name() ITrigger_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITrigger_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITrigger_nameContext)
}
func (s *Create_trigger_stmtContext) ON_() antlr.TerminalNode {
return s.GetToken(ParserON_, 0)
}
func (s *Create_trigger_stmtContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Create_trigger_stmtContext) BEGIN_() antlr.TerminalNode {
return s.GetToken(ParserBEGIN_, 0)
}
func (s *Create_trigger_stmtContext) END_() antlr.TerminalNode {
return s.GetToken(ParserEND_, 0)
}
func (s *Create_trigger_stmtContext) DELETE_() antlr.TerminalNode {
return s.GetToken(ParserDELETE_, 0)
}
func (s *Create_trigger_stmtContext) INSERT_() antlr.TerminalNode {
return s.GetToken(ParserINSERT_, 0)
}
func (s *Create_trigger_stmtContext) UPDATE_() antlr.TerminalNode {
return s.GetToken(ParserUPDATE_, 0)
}
func (s *Create_trigger_stmtContext) IF_() antlr.TerminalNode {
return s.GetToken(ParserIF_, 0)
}
func (s *Create_trigger_stmtContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *Create_trigger_stmtContext) EXISTS_() antlr.TerminalNode {
return s.GetToken(ParserEXISTS_, 0)
}
func (s *Create_trigger_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Create_trigger_stmtContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Create_trigger_stmtContext) BEFORE_() antlr.TerminalNode {
return s.GetToken(ParserBEFORE_, 0)
}
func (s *Create_trigger_stmtContext) AFTER_() antlr.TerminalNode {
return s.GetToken(ParserAFTER_, 0)
}
func (s *Create_trigger_stmtContext) INSTEAD_() antlr.TerminalNode {
return s.GetToken(ParserINSTEAD_, 0)
}
func (s *Create_trigger_stmtContext) AllOF_() []antlr.TerminalNode {
return s.GetTokens(ParserOF_)
}
func (s *Create_trigger_stmtContext) OF_(i int) antlr.TerminalNode {
return s.GetToken(ParserOF_, i)
}
func (s *Create_trigger_stmtContext) FOR_() antlr.TerminalNode {
return s.GetToken(ParserFOR_, 0)
}
func (s *Create_trigger_stmtContext) EACH_() antlr.TerminalNode {
return s.GetToken(ParserEACH_, 0)
}
func (s *Create_trigger_stmtContext) ROW_() antlr.TerminalNode {
return s.GetToken(ParserROW_, 0)
}
func (s *Create_trigger_stmtContext) WHEN_() antlr.TerminalNode {
return s.GetToken(ParserWHEN_, 0)
}
func (s *Create_trigger_stmtContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Create_trigger_stmtContext) AllSCOL() []antlr.TerminalNode {
return s.GetTokens(ParserSCOL)
}
func (s *Create_trigger_stmtContext) SCOL(i int) antlr.TerminalNode {
return s.GetToken(ParserSCOL, i)
}
func (s *Create_trigger_stmtContext) TEMP_() antlr.TerminalNode {
return s.GetToken(ParserTEMP_, 0)
}
func (s *Create_trigger_stmtContext) TEMPORARY_() antlr.TerminalNode {
return s.GetToken(ParserTEMPORARY_, 0)
}
func (s *Create_trigger_stmtContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Create_trigger_stmtContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Create_trigger_stmtContext) AllUpdate_stmt() []IUpdate_stmtContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IUpdate_stmtContext); ok {
len++
}
}
tst := make([]IUpdate_stmtContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IUpdate_stmtContext); ok {
tst[i] = t.(IUpdate_stmtContext)
i++
}
}
return tst
}
func (s *Create_trigger_stmtContext) Update_stmt(i int) IUpdate_stmtContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IUpdate_stmtContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IUpdate_stmtContext)
}
func (s *Create_trigger_stmtContext) AllInsert_stmt() []IInsert_stmtContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IInsert_stmtContext); ok {
len++
}
}
tst := make([]IInsert_stmtContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IInsert_stmtContext); ok {
tst[i] = t.(IInsert_stmtContext)
i++
}
}
return tst
}
func (s *Create_trigger_stmtContext) Insert_stmt(i int) IInsert_stmtContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IInsert_stmtContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IInsert_stmtContext)
}
func (s *Create_trigger_stmtContext) AllDelete_stmt() []IDelete_stmtContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IDelete_stmtContext); ok {
len++
}
}
tst := make([]IDelete_stmtContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IDelete_stmtContext); ok {
tst[i] = t.(IDelete_stmtContext)
i++
}
}
return tst
}
func (s *Create_trigger_stmtContext) Delete_stmt(i int) IDelete_stmtContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IDelete_stmtContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IDelete_stmtContext)
}
func (s *Create_trigger_stmtContext) AllSelect_stmt() []ISelect_stmtContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ISelect_stmtContext); ok {
len++
}
}
tst := make([]ISelect_stmtContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ISelect_stmtContext); ok {
tst[i] = t.(ISelect_stmtContext)
i++
}
}
return tst
}
func (s *Create_trigger_stmtContext) Select_stmt(i int) ISelect_stmtContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *Create_trigger_stmtContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Create_trigger_stmtContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Create_trigger_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Create_trigger_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Create_trigger_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCreate_trigger_stmt(s)
}
}
func (s *Create_trigger_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCreate_trigger_stmt(s)
}
}
func (s *Create_trigger_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCreate_trigger_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Create_trigger_stmt() (localctx ICreate_trigger_stmtContext) {
localctx = NewCreate_trigger_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 42, ParserRULE_create_trigger_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(633)
p.Match(ParserCREATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(635)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserTEMP_ || _la == ParserTEMPORARY_ {
{
p.SetState(634)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserTEMP_ || _la == ParserTEMPORARY_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
}
{
p.SetState(637)
p.Match(ParserTRIGGER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(641)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 70, p.GetParserRuleContext()) == 1 {
{
p.SetState(638)
p.Match(ParserIF_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(639)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(640)
p.Match(ParserEXISTS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(646)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 71, p.GetParserRuleContext()) == 1 {
{
p.SetState(643)
p.Schema_name()
}
{
p.SetState(644)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(648)
p.Trigger_name()
}
p.SetState(653)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserBEFORE_:
{
p.SetState(649)
p.Match(ParserBEFORE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserAFTER_:
{
p.SetState(650)
p.Match(ParserAFTER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserINSTEAD_:
{
p.SetState(651)
p.Match(ParserINSTEAD_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(652)
p.Match(ParserOF_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserDELETE_, ParserINSERT_, ParserUPDATE_:
default:
}
p.SetState(669)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserDELETE_:
{
p.SetState(655)
p.Match(ParserDELETE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserINSERT_:
{
p.SetState(656)
p.Match(ParserINSERT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserUPDATE_:
{
p.SetState(657)
p.Match(ParserUPDATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(667)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserOF_ {
{
p.SetState(658)
p.Match(ParserOF_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(659)
p.Column_name()
}
p.SetState(664)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(660)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(661)
p.Column_name()
}
p.SetState(666)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
{
p.SetState(671)
p.Match(ParserON_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(672)
p.Table_name()
}
p.SetState(676)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserFOR_ {
{
p.SetState(673)
p.Match(ParserFOR_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(674)
p.Match(ParserEACH_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(675)
p.Match(ParserROW_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
p.SetState(680)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWHEN_ {
{
p.SetState(678)
p.Match(ParserWHEN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(679)
p.expr(0)
}
}
{
p.SetState(682)
p.Match(ParserBEGIN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(691)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for ok := true; ok; ok = _la == ParserDELETE_ || ((int64((_la-88)) & ^0x3f) == 0 && ((int64(1)<<(_la-88))&2386912217732743169) != 0) {
p.SetState(687)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 78, p.GetParserRuleContext()) {
case 1:
{
p.SetState(683)
p.Update_stmt()
}
case 2:
{
p.SetState(684)
p.Insert_stmt()
}
case 3:
{
p.SetState(685)
p.Delete_stmt()
}
case 4:
{
p.SetState(686)
p.Select_stmt()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
{
p.SetState(689)
p.Match(ParserSCOL)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(693)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(695)
p.Match(ParserEND_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICreate_view_stmtContext is an interface to support dynamic dispatch.
type ICreate_view_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
CREATE_() antlr.TerminalNode
VIEW_() antlr.TerminalNode
View_name() IView_nameContext
AS_() antlr.TerminalNode
Select_stmt() ISelect_stmtContext
IF_() antlr.TerminalNode
NOT_() antlr.TerminalNode
EXISTS_() antlr.TerminalNode
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
OPEN_PAR() antlr.TerminalNode
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
CLOSE_PAR() antlr.TerminalNode
TEMP_() antlr.TerminalNode
TEMPORARY_() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsCreate_view_stmtContext differentiates from other interfaces.
IsCreate_view_stmtContext()
}
type Create_view_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyCreate_view_stmtContext() *Create_view_stmtContext {
var p = new(Create_view_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_create_view_stmt
return p
}
func InitEmptyCreate_view_stmtContext(p *Create_view_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_create_view_stmt
}
func (*Create_view_stmtContext) IsCreate_view_stmtContext() {}
func NewCreate_view_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Create_view_stmtContext {
var p = new(Create_view_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_create_view_stmt
return p
}
func (s *Create_view_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Create_view_stmtContext) CREATE_() antlr.TerminalNode {
return s.GetToken(ParserCREATE_, 0)
}
func (s *Create_view_stmtContext) VIEW_() antlr.TerminalNode {
return s.GetToken(ParserVIEW_, 0)
}
func (s *Create_view_stmtContext) View_name() IView_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IView_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IView_nameContext)
}
func (s *Create_view_stmtContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *Create_view_stmtContext) Select_stmt() ISelect_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *Create_view_stmtContext) IF_() antlr.TerminalNode {
return s.GetToken(ParserIF_, 0)
}
func (s *Create_view_stmtContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *Create_view_stmtContext) EXISTS_() antlr.TerminalNode {
return s.GetToken(ParserEXISTS_, 0)
}
func (s *Create_view_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Create_view_stmtContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Create_view_stmtContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Create_view_stmtContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Create_view_stmtContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Create_view_stmtContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Create_view_stmtContext) TEMP_() antlr.TerminalNode {
return s.GetToken(ParserTEMP_, 0)
}
func (s *Create_view_stmtContext) TEMPORARY_() antlr.TerminalNode {
return s.GetToken(ParserTEMPORARY_, 0)
}
func (s *Create_view_stmtContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Create_view_stmtContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Create_view_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Create_view_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Create_view_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCreate_view_stmt(s)
}
}
func (s *Create_view_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCreate_view_stmt(s)
}
}
func (s *Create_view_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCreate_view_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Create_view_stmt() (localctx ICreate_view_stmtContext) {
localctx = NewCreate_view_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 44, ParserRULE_create_view_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(697)
p.Match(ParserCREATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(699)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserTEMP_ || _la == ParserTEMPORARY_ {
{
p.SetState(698)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserTEMP_ || _la == ParserTEMPORARY_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
}
{
p.SetState(701)
p.Match(ParserVIEW_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(705)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 81, p.GetParserRuleContext()) == 1 {
{
p.SetState(702)
p.Match(ParserIF_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(703)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(704)
p.Match(ParserEXISTS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(710)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 82, p.GetParserRuleContext()) == 1 {
{
p.SetState(707)
p.Schema_name()
}
{
p.SetState(708)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(712)
p.View_name()
}
p.SetState(724)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserOPEN_PAR {
{
p.SetState(713)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(714)
p.Column_name()
}
p.SetState(719)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(715)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(716)
p.Column_name()
}
p.SetState(721)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(722)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(726)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(727)
p.Select_stmt()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICreate_virtual_table_stmtContext is an interface to support dynamic dispatch.
type ICreate_virtual_table_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
CREATE_() antlr.TerminalNode
VIRTUAL_() antlr.TerminalNode
TABLE_() antlr.TerminalNode
Table_name() ITable_nameContext
USING_() antlr.TerminalNode
Module_name() IModule_nameContext
IF_() antlr.TerminalNode
NOT_() antlr.TerminalNode
EXISTS_() antlr.TerminalNode
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
OPEN_PAR() antlr.TerminalNode
AllModule_argument() []IModule_argumentContext
Module_argument(i int) IModule_argumentContext
CLOSE_PAR() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsCreate_virtual_table_stmtContext differentiates from other interfaces.
IsCreate_virtual_table_stmtContext()
}
type Create_virtual_table_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyCreate_virtual_table_stmtContext() *Create_virtual_table_stmtContext {
var p = new(Create_virtual_table_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_create_virtual_table_stmt
return p
}
func InitEmptyCreate_virtual_table_stmtContext(p *Create_virtual_table_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_create_virtual_table_stmt
}
func (*Create_virtual_table_stmtContext) IsCreate_virtual_table_stmtContext() {}
func NewCreate_virtual_table_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Create_virtual_table_stmtContext {
var p = new(Create_virtual_table_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_create_virtual_table_stmt
return p
}
func (s *Create_virtual_table_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Create_virtual_table_stmtContext) CREATE_() antlr.TerminalNode {
return s.GetToken(ParserCREATE_, 0)
}
func (s *Create_virtual_table_stmtContext) VIRTUAL_() antlr.TerminalNode {
return s.GetToken(ParserVIRTUAL_, 0)
}
func (s *Create_virtual_table_stmtContext) TABLE_() antlr.TerminalNode {
return s.GetToken(ParserTABLE_, 0)
}
func (s *Create_virtual_table_stmtContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Create_virtual_table_stmtContext) USING_() antlr.TerminalNode {
return s.GetToken(ParserUSING_, 0)
}
func (s *Create_virtual_table_stmtContext) Module_name() IModule_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IModule_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IModule_nameContext)
}
func (s *Create_virtual_table_stmtContext) IF_() antlr.TerminalNode {
return s.GetToken(ParserIF_, 0)
}
func (s *Create_virtual_table_stmtContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *Create_virtual_table_stmtContext) EXISTS_() antlr.TerminalNode {
return s.GetToken(ParserEXISTS_, 0)
}
func (s *Create_virtual_table_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Create_virtual_table_stmtContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Create_virtual_table_stmtContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Create_virtual_table_stmtContext) AllModule_argument() []IModule_argumentContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IModule_argumentContext); ok {
len++
}
}
tst := make([]IModule_argumentContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IModule_argumentContext); ok {
tst[i] = t.(IModule_argumentContext)
i++
}
}
return tst
}
func (s *Create_virtual_table_stmtContext) Module_argument(i int) IModule_argumentContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IModule_argumentContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IModule_argumentContext)
}
func (s *Create_virtual_table_stmtContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Create_virtual_table_stmtContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Create_virtual_table_stmtContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Create_virtual_table_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Create_virtual_table_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Create_virtual_table_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCreate_virtual_table_stmt(s)
}
}
func (s *Create_virtual_table_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCreate_virtual_table_stmt(s)
}
}
func (s *Create_virtual_table_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCreate_virtual_table_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Create_virtual_table_stmt() (localctx ICreate_virtual_table_stmtContext) {
localctx = NewCreate_virtual_table_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 46, ParserRULE_create_virtual_table_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(729)
p.Match(ParserCREATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(730)
p.Match(ParserVIRTUAL_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(731)
p.Match(ParserTABLE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(735)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 85, p.GetParserRuleContext()) == 1 {
{
p.SetState(732)
p.Match(ParserIF_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(733)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(734)
p.Match(ParserEXISTS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(740)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 86, p.GetParserRuleContext()) == 1 {
{
p.SetState(737)
p.Schema_name()
}
{
p.SetState(738)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(742)
p.Table_name()
}
{
p.SetState(743)
p.Match(ParserUSING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(744)
p.Module_name()
}
p.SetState(756)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserOPEN_PAR {
{
p.SetState(745)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(746)
p.Module_argument()
}
p.SetState(751)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(747)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(748)
p.Module_argument()
}
p.SetState(753)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(754)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IWith_clauseContext is an interface to support dynamic dispatch.
type IWith_clauseContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
WITH_() antlr.TerminalNode
AllCte_table_name() []ICte_table_nameContext
Cte_table_name(i int) ICte_table_nameContext
AllAS_() []antlr.TerminalNode
AS_(i int) antlr.TerminalNode
AllOPEN_PAR() []antlr.TerminalNode
OPEN_PAR(i int) antlr.TerminalNode
AllSelect_stmt() []ISelect_stmtContext
Select_stmt(i int) ISelect_stmtContext
AllCLOSE_PAR() []antlr.TerminalNode
CLOSE_PAR(i int) antlr.TerminalNode
RECURSIVE_() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsWith_clauseContext differentiates from other interfaces.
IsWith_clauseContext()
}
type With_clauseContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyWith_clauseContext() *With_clauseContext {
var p = new(With_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_with_clause
return p
}
func InitEmptyWith_clauseContext(p *With_clauseContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_with_clause
}
func (*With_clauseContext) IsWith_clauseContext() {}
func NewWith_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *With_clauseContext {
var p = new(With_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_with_clause
return p
}
func (s *With_clauseContext) GetParser() antlr.Parser { return s.parser }
func (s *With_clauseContext) WITH_() antlr.TerminalNode {
return s.GetToken(ParserWITH_, 0)
}
func (s *With_clauseContext) AllCte_table_name() []ICte_table_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ICte_table_nameContext); ok {
len++
}
}
tst := make([]ICte_table_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ICte_table_nameContext); ok {
tst[i] = t.(ICte_table_nameContext)
i++
}
}
return tst
}
func (s *With_clauseContext) Cte_table_name(i int) ICte_table_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICte_table_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ICte_table_nameContext)
}
func (s *With_clauseContext) AllAS_() []antlr.TerminalNode {
return s.GetTokens(ParserAS_)
}
func (s *With_clauseContext) AS_(i int) antlr.TerminalNode {
return s.GetToken(ParserAS_, i)
}
func (s *With_clauseContext) AllOPEN_PAR() []antlr.TerminalNode {
return s.GetTokens(ParserOPEN_PAR)
}
func (s *With_clauseContext) OPEN_PAR(i int) antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, i)
}
func (s *With_clauseContext) AllSelect_stmt() []ISelect_stmtContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ISelect_stmtContext); ok {
len++
}
}
tst := make([]ISelect_stmtContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ISelect_stmtContext); ok {
tst[i] = t.(ISelect_stmtContext)
i++
}
}
return tst
}
func (s *With_clauseContext) Select_stmt(i int) ISelect_stmtContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *With_clauseContext) AllCLOSE_PAR() []antlr.TerminalNode {
return s.GetTokens(ParserCLOSE_PAR)
}
func (s *With_clauseContext) CLOSE_PAR(i int) antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, i)
}
func (s *With_clauseContext) RECURSIVE_() antlr.TerminalNode {
return s.GetToken(ParserRECURSIVE_, 0)
}
func (s *With_clauseContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *With_clauseContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *With_clauseContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *With_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *With_clauseContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterWith_clause(s)
}
}
func (s *With_clauseContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitWith_clause(s)
}
}
func (s *With_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitWith_clause(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) With_clause() (localctx IWith_clauseContext) {
localctx = NewWith_clauseContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 48, ParserRULE_with_clause)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(758)
p.Match(ParserWITH_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(760)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 89, p.GetParserRuleContext()) == 1 {
{
p.SetState(759)
p.Match(ParserRECURSIVE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(762)
p.Cte_table_name()
}
{
p.SetState(763)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(764)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(765)
p.Select_stmt()
}
{
p.SetState(766)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(776)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(767)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(768)
p.Cte_table_name()
}
{
p.SetState(769)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(770)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(771)
p.Select_stmt()
}
{
p.SetState(772)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(778)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICte_table_nameContext is an interface to support dynamic dispatch.
type ICte_table_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Table_name() ITable_nameContext
OPEN_PAR() antlr.TerminalNode
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
CLOSE_PAR() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsCte_table_nameContext differentiates from other interfaces.
IsCte_table_nameContext()
}
type Cte_table_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyCte_table_nameContext() *Cte_table_nameContext {
var p = new(Cte_table_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_cte_table_name
return p
}
func InitEmptyCte_table_nameContext(p *Cte_table_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_cte_table_name
}
func (*Cte_table_nameContext) IsCte_table_nameContext() {}
func NewCte_table_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Cte_table_nameContext {
var p = new(Cte_table_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_cte_table_name
return p
}
func (s *Cte_table_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Cte_table_nameContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Cte_table_nameContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Cte_table_nameContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Cte_table_nameContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Cte_table_nameContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Cte_table_nameContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Cte_table_nameContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Cte_table_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Cte_table_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Cte_table_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCte_table_name(s)
}
}
func (s *Cte_table_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCte_table_name(s)
}
}
func (s *Cte_table_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCte_table_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Cte_table_name() (localctx ICte_table_nameContext) {
localctx = NewCte_table_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 50, ParserRULE_cte_table_name)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(779)
p.Table_name()
}
p.SetState(791)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserOPEN_PAR {
{
p.SetState(780)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(781)
p.Column_name()
}
p.SetState(786)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(782)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(783)
p.Column_name()
}
p.SetState(788)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(789)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IRecursive_cteContext is an interface to support dynamic dispatch.
type IRecursive_cteContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Cte_table_name() ICte_table_nameContext
AS_() antlr.TerminalNode
OPEN_PAR() antlr.TerminalNode
Initial_select() IInitial_selectContext
UNION_() antlr.TerminalNode
Recursive_select() IRecursive_selectContext
CLOSE_PAR() antlr.TerminalNode
ALL_() antlr.TerminalNode
// IsRecursive_cteContext differentiates from other interfaces.
IsRecursive_cteContext()
}
type Recursive_cteContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyRecursive_cteContext() *Recursive_cteContext {
var p = new(Recursive_cteContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_recursive_cte
return p
}
func InitEmptyRecursive_cteContext(p *Recursive_cteContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_recursive_cte
}
func (*Recursive_cteContext) IsRecursive_cteContext() {}
func NewRecursive_cteContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Recursive_cteContext {
var p = new(Recursive_cteContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_recursive_cte
return p
}
func (s *Recursive_cteContext) GetParser() antlr.Parser { return s.parser }
func (s *Recursive_cteContext) Cte_table_name() ICte_table_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICte_table_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICte_table_nameContext)
}
func (s *Recursive_cteContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *Recursive_cteContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Recursive_cteContext) Initial_select() IInitial_selectContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IInitial_selectContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IInitial_selectContext)
}
func (s *Recursive_cteContext) UNION_() antlr.TerminalNode {
return s.GetToken(ParserUNION_, 0)
}
func (s *Recursive_cteContext) Recursive_select() IRecursive_selectContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IRecursive_selectContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IRecursive_selectContext)
}
func (s *Recursive_cteContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Recursive_cteContext) ALL_() antlr.TerminalNode {
return s.GetToken(ParserALL_, 0)
}
func (s *Recursive_cteContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Recursive_cteContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Recursive_cteContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterRecursive_cte(s)
}
}
func (s *Recursive_cteContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitRecursive_cte(s)
}
}
func (s *Recursive_cteContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitRecursive_cte(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Recursive_cte() (localctx IRecursive_cteContext) {
localctx = NewRecursive_cteContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 52, ParserRULE_recursive_cte)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(793)
p.Cte_table_name()
}
{
p.SetState(794)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(795)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(796)
p.Initial_select()
}
{
p.SetState(797)
p.Match(ParserUNION_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(799)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserALL_ {
{
p.SetState(798)
p.Match(ParserALL_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(801)
p.Recursive_select()
}
{
p.SetState(802)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICommon_table_expressionContext is an interface to support dynamic dispatch.
type ICommon_table_expressionContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Table_name() ITable_nameContext
AS_() antlr.TerminalNode
AllOPEN_PAR() []antlr.TerminalNode
OPEN_PAR(i int) antlr.TerminalNode
Select_stmt() ISelect_stmtContext
AllCLOSE_PAR() []antlr.TerminalNode
CLOSE_PAR(i int) antlr.TerminalNode
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsCommon_table_expressionContext differentiates from other interfaces.
IsCommon_table_expressionContext()
}
type Common_table_expressionContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyCommon_table_expressionContext() *Common_table_expressionContext {
var p = new(Common_table_expressionContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_common_table_expression
return p
}
func InitEmptyCommon_table_expressionContext(p *Common_table_expressionContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_common_table_expression
}
func (*Common_table_expressionContext) IsCommon_table_expressionContext() {}
func NewCommon_table_expressionContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Common_table_expressionContext {
var p = new(Common_table_expressionContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_common_table_expression
return p
}
func (s *Common_table_expressionContext) GetParser() antlr.Parser { return s.parser }
func (s *Common_table_expressionContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Common_table_expressionContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *Common_table_expressionContext) AllOPEN_PAR() []antlr.TerminalNode {
return s.GetTokens(ParserOPEN_PAR)
}
func (s *Common_table_expressionContext) OPEN_PAR(i int) antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, i)
}
func (s *Common_table_expressionContext) Select_stmt() ISelect_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *Common_table_expressionContext) AllCLOSE_PAR() []antlr.TerminalNode {
return s.GetTokens(ParserCLOSE_PAR)
}
func (s *Common_table_expressionContext) CLOSE_PAR(i int) antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, i)
}
func (s *Common_table_expressionContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Common_table_expressionContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Common_table_expressionContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Common_table_expressionContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Common_table_expressionContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Common_table_expressionContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Common_table_expressionContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCommon_table_expression(s)
}
}
func (s *Common_table_expressionContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCommon_table_expression(s)
}
}
func (s *Common_table_expressionContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCommon_table_expression(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Common_table_expression() (localctx ICommon_table_expressionContext) {
localctx = NewCommon_table_expressionContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 54, ParserRULE_common_table_expression)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(804)
p.Table_name()
}
p.SetState(816)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserOPEN_PAR {
{
p.SetState(805)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(806)
p.Column_name()
}
p.SetState(811)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(807)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(808)
p.Column_name()
}
p.SetState(813)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(814)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(818)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(819)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(820)
p.Select_stmt()
}
{
p.SetState(821)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IDelete_stmtContext is an interface to support dynamic dispatch.
type IDelete_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
DELETE_() antlr.TerminalNode
FROM_() antlr.TerminalNode
Qualified_table_name() IQualified_table_nameContext
With_clause() IWith_clauseContext
WHERE_() antlr.TerminalNode
Expr() IExprContext
Returning_clause() IReturning_clauseContext
// IsDelete_stmtContext differentiates from other interfaces.
IsDelete_stmtContext()
}
type Delete_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyDelete_stmtContext() *Delete_stmtContext {
var p = new(Delete_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_delete_stmt
return p
}
func InitEmptyDelete_stmtContext(p *Delete_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_delete_stmt
}
func (*Delete_stmtContext) IsDelete_stmtContext() {}
func NewDelete_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Delete_stmtContext {
var p = new(Delete_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_delete_stmt
return p
}
func (s *Delete_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Delete_stmtContext) DELETE_() antlr.TerminalNode {
return s.GetToken(ParserDELETE_, 0)
}
func (s *Delete_stmtContext) FROM_() antlr.TerminalNode {
return s.GetToken(ParserFROM_, 0)
}
func (s *Delete_stmtContext) Qualified_table_name() IQualified_table_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IQualified_table_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IQualified_table_nameContext)
}
func (s *Delete_stmtContext) With_clause() IWith_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IWith_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IWith_clauseContext)
}
func (s *Delete_stmtContext) WHERE_() antlr.TerminalNode {
return s.GetToken(ParserWHERE_, 0)
}
func (s *Delete_stmtContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Delete_stmtContext) Returning_clause() IReturning_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IReturning_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IReturning_clauseContext)
}
func (s *Delete_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Delete_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Delete_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterDelete_stmt(s)
}
}
func (s *Delete_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitDelete_stmt(s)
}
}
func (s *Delete_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitDelete_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Delete_stmt() (localctx IDelete_stmtContext) {
localctx = NewDelete_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 56, ParserRULE_delete_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(824)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWITH_ {
{
p.SetState(823)
p.With_clause()
}
}
{
p.SetState(826)
p.Match(ParserDELETE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(827)
p.Match(ParserFROM_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(828)
p.Qualified_table_name()
}
p.SetState(831)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWHERE_ {
{
p.SetState(829)
p.Match(ParserWHERE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(830)
p.expr(0)
}
}
p.SetState(834)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserRETURNING_ {
{
p.SetState(833)
p.Returning_clause()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IDelete_stmt_limitedContext is an interface to support dynamic dispatch.
type IDelete_stmt_limitedContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
DELETE_() antlr.TerminalNode
FROM_() antlr.TerminalNode
Qualified_table_name() IQualified_table_nameContext
With_clause() IWith_clauseContext
WHERE_() antlr.TerminalNode
Expr() IExprContext
Returning_clause() IReturning_clauseContext
Limit_stmt() ILimit_stmtContext
Order_by_stmt() IOrder_by_stmtContext
// IsDelete_stmt_limitedContext differentiates from other interfaces.
IsDelete_stmt_limitedContext()
}
type Delete_stmt_limitedContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyDelete_stmt_limitedContext() *Delete_stmt_limitedContext {
var p = new(Delete_stmt_limitedContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_delete_stmt_limited
return p
}
func InitEmptyDelete_stmt_limitedContext(p *Delete_stmt_limitedContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_delete_stmt_limited
}
func (*Delete_stmt_limitedContext) IsDelete_stmt_limitedContext() {}
func NewDelete_stmt_limitedContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Delete_stmt_limitedContext {
var p = new(Delete_stmt_limitedContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_delete_stmt_limited
return p
}
func (s *Delete_stmt_limitedContext) GetParser() antlr.Parser { return s.parser }
func (s *Delete_stmt_limitedContext) DELETE_() antlr.TerminalNode {
return s.GetToken(ParserDELETE_, 0)
}
func (s *Delete_stmt_limitedContext) FROM_() antlr.TerminalNode {
return s.GetToken(ParserFROM_, 0)
}
func (s *Delete_stmt_limitedContext) Qualified_table_name() IQualified_table_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IQualified_table_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IQualified_table_nameContext)
}
func (s *Delete_stmt_limitedContext) With_clause() IWith_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IWith_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IWith_clauseContext)
}
func (s *Delete_stmt_limitedContext) WHERE_() antlr.TerminalNode {
return s.GetToken(ParserWHERE_, 0)
}
func (s *Delete_stmt_limitedContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Delete_stmt_limitedContext) Returning_clause() IReturning_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IReturning_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IReturning_clauseContext)
}
func (s *Delete_stmt_limitedContext) Limit_stmt() ILimit_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ILimit_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ILimit_stmtContext)
}
func (s *Delete_stmt_limitedContext) Order_by_stmt() IOrder_by_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOrder_by_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IOrder_by_stmtContext)
}
func (s *Delete_stmt_limitedContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Delete_stmt_limitedContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Delete_stmt_limitedContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterDelete_stmt_limited(s)
}
}
func (s *Delete_stmt_limitedContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitDelete_stmt_limited(s)
}
}
func (s *Delete_stmt_limitedContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitDelete_stmt_limited(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Delete_stmt_limited() (localctx IDelete_stmt_limitedContext) {
localctx = NewDelete_stmt_limitedContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 58, ParserRULE_delete_stmt_limited)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(837)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWITH_ {
{
p.SetState(836)
p.With_clause()
}
}
{
p.SetState(839)
p.Match(ParserDELETE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(840)
p.Match(ParserFROM_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(841)
p.Qualified_table_name()
}
p.SetState(844)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWHERE_ {
{
p.SetState(842)
p.Match(ParserWHERE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(843)
p.expr(0)
}
}
p.SetState(847)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserRETURNING_ {
{
p.SetState(846)
p.Returning_clause()
}
}
p.SetState(853)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserLIMIT_ || _la == ParserORDER_ {
p.SetState(850)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserORDER_ {
{
p.SetState(849)
p.Order_by_stmt()
}
}
{
p.SetState(852)
p.Limit_stmt()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IDetach_stmtContext is an interface to support dynamic dispatch.
type IDetach_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
DETACH_() antlr.TerminalNode
Schema_name() ISchema_nameContext
DATABASE_() antlr.TerminalNode
// IsDetach_stmtContext differentiates from other interfaces.
IsDetach_stmtContext()
}
type Detach_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyDetach_stmtContext() *Detach_stmtContext {
var p = new(Detach_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_detach_stmt
return p
}
func InitEmptyDetach_stmtContext(p *Detach_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_detach_stmt
}
func (*Detach_stmtContext) IsDetach_stmtContext() {}
func NewDetach_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Detach_stmtContext {
var p = new(Detach_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_detach_stmt
return p
}
func (s *Detach_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Detach_stmtContext) DETACH_() antlr.TerminalNode {
return s.GetToken(ParserDETACH_, 0)
}
func (s *Detach_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Detach_stmtContext) DATABASE_() antlr.TerminalNode {
return s.GetToken(ParserDATABASE_, 0)
}
func (s *Detach_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Detach_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Detach_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterDetach_stmt(s)
}
}
func (s *Detach_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitDetach_stmt(s)
}
}
func (s *Detach_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitDetach_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Detach_stmt() (localctx IDetach_stmtContext) {
localctx = NewDetach_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 60, ParserRULE_detach_stmt)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(855)
p.Match(ParserDETACH_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(857)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 104, p.GetParserRuleContext()) == 1 {
{
p.SetState(856)
p.Match(ParserDATABASE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(859)
p.Schema_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IDrop_stmtContext is an interface to support dynamic dispatch.
type IDrop_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetObject returns the object token.
GetObject() antlr.Token
// SetObject sets the object token.
SetObject(antlr.Token)
// Getter signatures
DROP_() antlr.TerminalNode
Any_name() IAny_nameContext
INDEX_() antlr.TerminalNode
TABLE_() antlr.TerminalNode
TRIGGER_() antlr.TerminalNode
VIEW_() antlr.TerminalNode
IF_() antlr.TerminalNode
EXISTS_() antlr.TerminalNode
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
// IsDrop_stmtContext differentiates from other interfaces.
IsDrop_stmtContext()
}
type Drop_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
object antlr.Token
}
func NewEmptyDrop_stmtContext() *Drop_stmtContext {
var p = new(Drop_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_drop_stmt
return p
}
func InitEmptyDrop_stmtContext(p *Drop_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_drop_stmt
}
func (*Drop_stmtContext) IsDrop_stmtContext() {}
func NewDrop_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Drop_stmtContext {
var p = new(Drop_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_drop_stmt
return p
}
func (s *Drop_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Drop_stmtContext) GetObject() antlr.Token { return s.object }
func (s *Drop_stmtContext) SetObject(v antlr.Token) { s.object = v }
func (s *Drop_stmtContext) DROP_() antlr.TerminalNode {
return s.GetToken(ParserDROP_, 0)
}
func (s *Drop_stmtContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Drop_stmtContext) INDEX_() antlr.TerminalNode {
return s.GetToken(ParserINDEX_, 0)
}
func (s *Drop_stmtContext) TABLE_() antlr.TerminalNode {
return s.GetToken(ParserTABLE_, 0)
}
func (s *Drop_stmtContext) TRIGGER_() antlr.TerminalNode {
return s.GetToken(ParserTRIGGER_, 0)
}
func (s *Drop_stmtContext) VIEW_() antlr.TerminalNode {
return s.GetToken(ParserVIEW_, 0)
}
func (s *Drop_stmtContext) IF_() antlr.TerminalNode {
return s.GetToken(ParserIF_, 0)
}
func (s *Drop_stmtContext) EXISTS_() antlr.TerminalNode {
return s.GetToken(ParserEXISTS_, 0)
}
func (s *Drop_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Drop_stmtContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Drop_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Drop_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Drop_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterDrop_stmt(s)
}
}
func (s *Drop_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitDrop_stmt(s)
}
}
func (s *Drop_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitDrop_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Drop_stmt() (localctx IDrop_stmtContext) {
localctx = NewDrop_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 62, ParserRULE_drop_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(861)
p.Match(ParserDROP_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(862)
var _lt = p.GetTokenStream().LT(1)
localctx.(*Drop_stmtContext).object = _lt
_la = p.GetTokenStream().LA(1)
if !((int64((_la-84)) & ^0x3f) == 0 && ((int64(1)<<(_la-84))&2324138882699886593) != 0) {
var _ri = p.GetErrorHandler().RecoverInline(p)
localctx.(*Drop_stmtContext).object = _ri
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
p.SetState(865)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 105, p.GetParserRuleContext()) == 1 {
{
p.SetState(863)
p.Match(ParserIF_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(864)
p.Match(ParserEXISTS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(870)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 106, p.GetParserRuleContext()) == 1 {
{
p.SetState(867)
p.Schema_name()
}
{
p.SetState(868)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(872)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IExprContext is an interface to support dynamic dispatch.
type IExprContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Literal_value() ILiteral_valueContext
BIND_PARAMETER() antlr.TerminalNode
Column_name() IColumn_nameContext
Table_name() ITable_nameContext
AllDOT() []antlr.TerminalNode
DOT(i int) antlr.TerminalNode
Schema_name() ISchema_nameContext
Unary_operator() IUnary_operatorContext
AllExpr() []IExprContext
Expr(i int) IExprContext
Function_name() IFunction_nameContext
OPEN_PAR() antlr.TerminalNode
CLOSE_PAR() antlr.TerminalNode
STAR() antlr.TerminalNode
Filter_clause() IFilter_clauseContext
Over_clause() IOver_clauseContext
DISTINCT_() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
CAST_() antlr.TerminalNode
AS_() antlr.TerminalNode
Type_name() IType_nameContext
Select_stmt() ISelect_stmtContext
EXISTS_() antlr.TerminalNode
NOT_() antlr.TerminalNode
CASE_() antlr.TerminalNode
END_() antlr.TerminalNode
AllWHEN_() []antlr.TerminalNode
WHEN_(i int) antlr.TerminalNode
AllTHEN_() []antlr.TerminalNode
THEN_(i int) antlr.TerminalNode
ELSE_() antlr.TerminalNode
Raise_function() IRaise_functionContext
PIPE2() antlr.TerminalNode
DIV() antlr.TerminalNode
MOD() antlr.TerminalNode
PLUS() antlr.TerminalNode
MINUS() antlr.TerminalNode
LT2() antlr.TerminalNode
GT2() antlr.TerminalNode
AMP() antlr.TerminalNode
PIPE() antlr.TerminalNode
LT() antlr.TerminalNode
LT_EQ() antlr.TerminalNode
GT() antlr.TerminalNode
GT_EQ() antlr.TerminalNode
ASSIGN() antlr.TerminalNode
EQ() antlr.TerminalNode
NOT_EQ1() antlr.TerminalNode
NOT_EQ2() antlr.TerminalNode
IS_() antlr.TerminalNode
IN_() antlr.TerminalNode
LIKE_() antlr.TerminalNode
GLOB_() antlr.TerminalNode
MATCH_() antlr.TerminalNode
REGEXP_() antlr.TerminalNode
AND_() antlr.TerminalNode
OR_() antlr.TerminalNode
BETWEEN_() antlr.TerminalNode
COLLATE_() antlr.TerminalNode
Collation_name() ICollation_nameContext
ESCAPE_() antlr.TerminalNode
ISNULL_() antlr.TerminalNode
NOTNULL_() antlr.TerminalNode
NULL_() antlr.TerminalNode
Table_function_name() ITable_function_nameContext
// IsExprContext differentiates from other interfaces.
IsExprContext()
}
type ExprContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyExprContext() *ExprContext {
var p = new(ExprContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_expr
return p
}
func InitEmptyExprContext(p *ExprContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_expr
}
func (*ExprContext) IsExprContext() {}
func NewExprContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ExprContext {
var p = new(ExprContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_expr
return p
}
func (s *ExprContext) GetParser() antlr.Parser { return s.parser }
func (s *ExprContext) Literal_value() ILiteral_valueContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ILiteral_valueContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ILiteral_valueContext)
}
func (s *ExprContext) BIND_PARAMETER() antlr.TerminalNode {
return s.GetToken(ParserBIND_PARAMETER, 0)
}
func (s *ExprContext) Column_name() IColumn_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *ExprContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *ExprContext) AllDOT() []antlr.TerminalNode {
return s.GetTokens(ParserDOT)
}
func (s *ExprContext) DOT(i int) antlr.TerminalNode {
return s.GetToken(ParserDOT, i)
}
func (s *ExprContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *ExprContext) Unary_operator() IUnary_operatorContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IUnary_operatorContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IUnary_operatorContext)
}
func (s *ExprContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *ExprContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *ExprContext) Function_name() IFunction_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFunction_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFunction_nameContext)
}
func (s *ExprContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *ExprContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *ExprContext) STAR() antlr.TerminalNode {
return s.GetToken(ParserSTAR, 0)
}
func (s *ExprContext) Filter_clause() IFilter_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFilter_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFilter_clauseContext)
}
func (s *ExprContext) Over_clause() IOver_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOver_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IOver_clauseContext)
}
func (s *ExprContext) DISTINCT_() antlr.TerminalNode {
return s.GetToken(ParserDISTINCT_, 0)
}
func (s *ExprContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *ExprContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *ExprContext) CAST_() antlr.TerminalNode {
return s.GetToken(ParserCAST_, 0)
}
func (s *ExprContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *ExprContext) Type_name() IType_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IType_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IType_nameContext)
}
func (s *ExprContext) Select_stmt() ISelect_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *ExprContext) EXISTS_() antlr.TerminalNode {
return s.GetToken(ParserEXISTS_, 0)
}
func (s *ExprContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *ExprContext) CASE_() antlr.TerminalNode {
return s.GetToken(ParserCASE_, 0)
}
func (s *ExprContext) END_() antlr.TerminalNode {
return s.GetToken(ParserEND_, 0)
}
func (s *ExprContext) AllWHEN_() []antlr.TerminalNode {
return s.GetTokens(ParserWHEN_)
}
func (s *ExprContext) WHEN_(i int) antlr.TerminalNode {
return s.GetToken(ParserWHEN_, i)
}
func (s *ExprContext) AllTHEN_() []antlr.TerminalNode {
return s.GetTokens(ParserTHEN_)
}
func (s *ExprContext) THEN_(i int) antlr.TerminalNode {
return s.GetToken(ParserTHEN_, i)
}
func (s *ExprContext) ELSE_() antlr.TerminalNode {
return s.GetToken(ParserELSE_, 0)
}
func (s *ExprContext) Raise_function() IRaise_functionContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IRaise_functionContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IRaise_functionContext)
}
func (s *ExprContext) PIPE2() antlr.TerminalNode {
return s.GetToken(ParserPIPE2, 0)
}
func (s *ExprContext) DIV() antlr.TerminalNode {
return s.GetToken(ParserDIV, 0)
}
func (s *ExprContext) MOD() antlr.TerminalNode {
return s.GetToken(ParserMOD, 0)
}
func (s *ExprContext) PLUS() antlr.TerminalNode {
return s.GetToken(ParserPLUS, 0)
}
func (s *ExprContext) MINUS() antlr.TerminalNode {
return s.GetToken(ParserMINUS, 0)
}
func (s *ExprContext) LT2() antlr.TerminalNode {
return s.GetToken(ParserLT2, 0)
}
func (s *ExprContext) GT2() antlr.TerminalNode {
return s.GetToken(ParserGT2, 0)
}
func (s *ExprContext) AMP() antlr.TerminalNode {
return s.GetToken(ParserAMP, 0)
}
func (s *ExprContext) PIPE() antlr.TerminalNode {
return s.GetToken(ParserPIPE, 0)
}
func (s *ExprContext) LT() antlr.TerminalNode {
return s.GetToken(ParserLT, 0)
}
func (s *ExprContext) LT_EQ() antlr.TerminalNode {
return s.GetToken(ParserLT_EQ, 0)
}
func (s *ExprContext) GT() antlr.TerminalNode {
return s.GetToken(ParserGT, 0)
}
func (s *ExprContext) GT_EQ() antlr.TerminalNode {
return s.GetToken(ParserGT_EQ, 0)
}
func (s *ExprContext) ASSIGN() antlr.TerminalNode {
return s.GetToken(ParserASSIGN, 0)
}
func (s *ExprContext) EQ() antlr.TerminalNode {
return s.GetToken(ParserEQ, 0)
}
func (s *ExprContext) NOT_EQ1() antlr.TerminalNode {
return s.GetToken(ParserNOT_EQ1, 0)
}
func (s *ExprContext) NOT_EQ2() antlr.TerminalNode {
return s.GetToken(ParserNOT_EQ2, 0)
}
func (s *ExprContext) IS_() antlr.TerminalNode {
return s.GetToken(ParserIS_, 0)
}
func (s *ExprContext) IN_() antlr.TerminalNode {
return s.GetToken(ParserIN_, 0)
}
func (s *ExprContext) LIKE_() antlr.TerminalNode {
return s.GetToken(ParserLIKE_, 0)
}
func (s *ExprContext) GLOB_() antlr.TerminalNode {
return s.GetToken(ParserGLOB_, 0)
}
func (s *ExprContext) MATCH_() antlr.TerminalNode {
return s.GetToken(ParserMATCH_, 0)
}
func (s *ExprContext) REGEXP_() antlr.TerminalNode {
return s.GetToken(ParserREGEXP_, 0)
}
func (s *ExprContext) AND_() antlr.TerminalNode {
return s.GetToken(ParserAND_, 0)
}
func (s *ExprContext) OR_() antlr.TerminalNode {
return s.GetToken(ParserOR_, 0)
}
func (s *ExprContext) BETWEEN_() antlr.TerminalNode {
return s.GetToken(ParserBETWEEN_, 0)
}
func (s *ExprContext) COLLATE_() antlr.TerminalNode {
return s.GetToken(ParserCOLLATE_, 0)
}
func (s *ExprContext) Collation_name() ICollation_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICollation_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICollation_nameContext)
}
func (s *ExprContext) ESCAPE_() antlr.TerminalNode {
return s.GetToken(ParserESCAPE_, 0)
}
func (s *ExprContext) ISNULL_() antlr.TerminalNode {
return s.GetToken(ParserISNULL_, 0)
}
func (s *ExprContext) NOTNULL_() antlr.TerminalNode {
return s.GetToken(ParserNOTNULL_, 0)
}
func (s *ExprContext) NULL_() antlr.TerminalNode {
return s.GetToken(ParserNULL_, 0)
}
func (s *ExprContext) Table_function_name() ITable_function_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_function_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_function_nameContext)
}
func (s *ExprContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ExprContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ExprContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterExpr(s)
}
}
func (s *ExprContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitExpr(s)
}
}
func (s *ExprContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitExpr(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Expr() (localctx IExprContext) {
return p.expr(0)
}
func (p *Parser) expr(_p int) (localctx IExprContext) {
var _parentctx antlr.ParserRuleContext = p.GetParserRuleContext()
_parentState := p.GetState()
localctx = NewExprContext(p, p.GetParserRuleContext(), _parentState)
var _prevctx IExprContext = localctx
var _ antlr.ParserRuleContext = _prevctx // TODO: To prevent unused variable warning.
_startState := 64
p.EnterRecursionRule(localctx, 64, ParserRULE_expr, _p)
var _la int
var _alt int
p.EnterOuterAlt(localctx, 1)
p.SetState(962)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 120, p.GetParserRuleContext()) {
case 1:
{
p.SetState(875)
p.Literal_value()
}
case 2:
{
p.SetState(876)
p.Match(ParserBIND_PARAMETER)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 3:
p.SetState(885)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 108, p.GetParserRuleContext()) == 1 {
p.SetState(880)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 107, p.GetParserRuleContext()) == 1 {
{
p.SetState(877)
p.Schema_name()
}
{
p.SetState(878)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(882)
p.Table_name()
}
{
p.SetState(883)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(887)
p.Column_name()
}
case 4:
{
p.SetState(888)
p.Unary_operator()
}
{
p.SetState(889)
p.expr(21)
}
case 5:
{
p.SetState(891)
p.Function_name()
}
{
p.SetState(892)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(905)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserOPEN_PAR, ParserPLUS, ParserMINUS, ParserTILDE, ParserABORT_, ParserACTION_, ParserADD_, ParserAFTER_, ParserALL_, ParserALTER_, ParserANALYZE_, ParserAND_, ParserAS_, ParserASC_, ParserATTACH_, ParserAUTOINCREMENT_, ParserBEFORE_, ParserBEGIN_, ParserBETWEEN_, ParserBY_, ParserCASCADE_, ParserCASE_, ParserCAST_, ParserCHECK_, ParserCOLLATE_, ParserCOLUMN_, ParserCOMMIT_, ParserCONFLICT_, ParserCONSTRAINT_, ParserCREATE_, ParserCROSS_, ParserCURRENT_DATE_, ParserCURRENT_TIME_, ParserCURRENT_TIMESTAMP_, ParserDATABASE_, ParserDEFAULT_, ParserDEFERRABLE_, ParserDEFERRED_, ParserDELETE_, ParserDESC_, ParserDETACH_, ParserDISTINCT_, ParserDROP_, ParserEACH_, ParserELSE_, ParserEND_, ParserESCAPE_, ParserEXCEPT_, ParserEXCLUSIVE_, ParserEXISTS_, ParserEXPLAIN_, ParserFAIL_, ParserFOR_, ParserFOREIGN_, ParserFROM_, ParserFULL_, ParserGLOB_, ParserGROUP_, ParserHAVING_, ParserIF_, ParserIGNORE_, ParserIMMEDIATE_, ParserIN_, ParserINDEX_, ParserINDEXED_, ParserINITIALLY_, ParserINNER_, ParserINSERT_, ParserINSTEAD_, ParserINTERSECT_, ParserINTO_, ParserIS_, ParserISNULL_, ParserJOIN_, ParserKEY_, ParserLEFT_, ParserLIKE_, ParserLIMIT_, ParserMATCH_, ParserNATURAL_, ParserNO_, ParserNOT_, ParserNOTNULL_, ParserNULL_, ParserOF_, ParserOFFSET_, ParserON_, ParserOR_, ParserORDER_, ParserOUTER_, ParserPLAN_, ParserPRAGMA_, ParserPRIMARY_, ParserQUERY_, ParserRAISE_, ParserRECURSIVE_, ParserREFERENCES_, ParserREGEXP_, ParserREINDEX_, ParserRELEASE_, ParserRENAME_, ParserREPLACE_, ParserRESTRICT_, ParserRIGHT_, ParserROLLBACK_, ParserROW_, ParserROWS_, ParserSAVEPOINT_, ParserSELECT_, ParserSET_, ParserTABLE_, ParserTEMP_, ParserTEMPORARY_, ParserTHEN_, ParserTO_, ParserTRANSACTION_, ParserTRIGGER_, ParserUNION_, ParserUNIQUE_, ParserUPDATE_, ParserUSING_, ParserVACUUM_, ParserVALUES_, ParserVIEW_, ParserVIRTUAL_, ParserWHEN_, ParserWHERE_, ParserWITH_, ParserWITHOUT_, ParserFIRST_VALUE_, ParserOVER_, ParserPARTITION_, ParserRANGE_, ParserPRECEDING_, ParserUNBOUNDED_, ParserCURRENT_, ParserFOLLOWING_, ParserCUME_DIST_, ParserDENSE_RANK_, ParserLAG_, ParserLAST_VALUE_, ParserLEAD_, ParserNTH_VALUE_, ParserNTILE_, ParserPERCENT_RANK_, ParserRANK_, ParserROW_NUMBER_, ParserGENERATED_, ParserALWAYS_, ParserSTORED_, ParserTRUE_, ParserFALSE_, ParserWINDOW_, ParserNULLS_, ParserFIRST_, ParserLAST_, ParserFILTER_, ParserGROUPS_, ParserEXCLUDE_, ParserIDENTIFIER, ParserNUMERIC_LITERAL, ParserBIND_PARAMETER, ParserSTRING_LITERAL, ParserBLOB_LITERAL:
p.SetState(894)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 109, p.GetParserRuleContext()) == 1 {
{
p.SetState(893)
p.Match(ParserDISTINCT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(896)
p.expr(0)
}
p.SetState(901)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(897)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(898)
p.expr(0)
}
p.SetState(903)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
case ParserSTAR:
{
p.SetState(904)
p.Match(ParserSTAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserCLOSE_PAR:
default:
}
{
p.SetState(907)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(909)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 112, p.GetParserRuleContext()) == 1 {
{
p.SetState(908)
p.Filter_clause()
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(912)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 113, p.GetParserRuleContext()) == 1 {
{
p.SetState(911)
p.Over_clause()
}
} else if p.HasError() { // JIM
goto errorExit
}
case 6:
{
p.SetState(914)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(915)
p.expr(0)
}
p.SetState(920)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(916)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(917)
p.expr(0)
}
p.SetState(922)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(923)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 7:
{
p.SetState(925)
p.Match(ParserCAST_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(926)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(927)
p.expr(0)
}
{
p.SetState(928)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(929)
p.Type_name()
}
{
p.SetState(930)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 8:
p.SetState(936)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserEXISTS_ || _la == ParserNOT_ {
p.SetState(933)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserNOT_ {
{
p.SetState(932)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(935)
p.Match(ParserEXISTS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(938)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(939)
p.Select_stmt()
}
{
p.SetState(940)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 9:
{
p.SetState(942)
p.Match(ParserCASE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(944)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 117, p.GetParserRuleContext()) == 1 {
{
p.SetState(943)
p.expr(0)
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(951)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for ok := true; ok; ok = _la == ParserWHEN_ {
{
p.SetState(946)
p.Match(ParserWHEN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(947)
p.expr(0)
}
{
p.SetState(948)
p.Match(ParserTHEN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(949)
p.expr(0)
}
p.SetState(953)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
p.SetState(957)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserELSE_ {
{
p.SetState(955)
p.Match(ParserELSE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(956)
p.expr(0)
}
}
{
p.SetState(959)
p.Match(ParserEND_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 10:
{
p.SetState(961)
p.Raise_function()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
p.GetParserRuleContext().SetStop(p.GetTokenStream().LT(-1))
p.SetState(1083)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 136, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
for _alt != 2 && _alt != antlr.ATNInvalidAltNumber {
if _alt == 1 {
if p.GetParseListeners() != nil {
p.TriggerExitRuleEvent()
}
_prevctx = localctx
p.SetState(1081)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 135, p.GetParserRuleContext()) {
case 1:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(964)
if !(p.Precpred(p.GetParserRuleContext(), 20)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 20)", ""))
goto errorExit
}
{
p.SetState(965)
p.Match(ParserPIPE2)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(966)
p.expr(21)
}
case 2:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(967)
if !(p.Precpred(p.GetParserRuleContext(), 19)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 19)", ""))
goto errorExit
}
{
p.SetState(968)
_la = p.GetTokenStream().LA(1)
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&12416) != 0) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
{
p.SetState(969)
p.expr(20)
}
case 3:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(970)
if !(p.Precpred(p.GetParserRuleContext(), 18)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 18)", ""))
goto errorExit
}
{
p.SetState(971)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserPLUS || _la == ParserMINUS) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
{
p.SetState(972)
p.expr(19)
}
case 4:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(973)
if !(p.Precpred(p.GetParserRuleContext(), 17)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 17)", ""))
goto errorExit
}
{
p.SetState(974)
_la = p.GetTokenStream().LA(1)
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&245760) != 0) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
{
p.SetState(975)
p.expr(18)
}
case 5:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(976)
if !(p.Precpred(p.GetParserRuleContext(), 16)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 16)", ""))
goto errorExit
}
{
p.SetState(977)
_la = p.GetTokenStream().LA(1)
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&3932160) != 0) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
{
p.SetState(978)
p.expr(17)
}
case 6:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(979)
if !(p.Precpred(p.GetParserRuleContext(), 15)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 15)", ""))
goto errorExit
}
p.SetState(992)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 121, p.GetParserRuleContext()) {
case 1:
{
p.SetState(980)
p.Match(ParserASSIGN)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 2:
{
p.SetState(981)
p.Match(ParserEQ)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 3:
{
p.SetState(982)
p.Match(ParserNOT_EQ1)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 4:
{
p.SetState(983)
p.Match(ParserNOT_EQ2)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 5:
{
p.SetState(984)
p.Match(ParserIS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 6:
{
p.SetState(985)
p.Match(ParserIS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(986)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 7:
{
p.SetState(987)
p.Match(ParserIN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 8:
{
p.SetState(988)
p.Match(ParserLIKE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 9:
{
p.SetState(989)
p.Match(ParserGLOB_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 10:
{
p.SetState(990)
p.Match(ParserMATCH_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 11:
{
p.SetState(991)
p.Match(ParserREGEXP_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
{
p.SetState(994)
p.expr(16)
}
case 7:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(995)
if !(p.Precpred(p.GetParserRuleContext(), 14)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 14)", ""))
goto errorExit
}
{
p.SetState(996)
p.Match(ParserAND_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(997)
p.expr(15)
}
case 8:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(998)
if !(p.Precpred(p.GetParserRuleContext(), 13)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 13)", ""))
goto errorExit
}
{
p.SetState(999)
p.Match(ParserOR_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1000)
p.expr(14)
}
case 9:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(1001)
if !(p.Precpred(p.GetParserRuleContext(), 6)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 6)", ""))
goto errorExit
}
{
p.SetState(1002)
p.Match(ParserIS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1004)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 122, p.GetParserRuleContext()) == 1 {
{
p.SetState(1003)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1006)
p.expr(7)
}
case 10:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(1007)
if !(p.Precpred(p.GetParserRuleContext(), 5)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 5)", ""))
goto errorExit
}
p.SetState(1009)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserNOT_ {
{
p.SetState(1008)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(1011)
p.Match(ParserBETWEEN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1012)
p.expr(0)
}
{
p.SetState(1013)
p.Match(ParserAND_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1014)
p.expr(6)
}
case 11:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(1016)
if !(p.Precpred(p.GetParserRuleContext(), 9)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 9)", ""))
goto errorExit
}
{
p.SetState(1017)
p.Match(ParserCOLLATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1018)
p.Collation_name()
}
case 12:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(1019)
if !(p.Precpred(p.GetParserRuleContext(), 8)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 8)", ""))
goto errorExit
}
p.SetState(1021)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserNOT_ {
{
p.SetState(1020)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(1023)
_la = p.GetTokenStream().LA(1)
if !((int64((_la-77)) & ^0x3f) == 0 && ((int64(1)<<(_la-77))&2199028498433) != 0) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
{
p.SetState(1024)
p.expr(0)
}
p.SetState(1027)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 125, p.GetParserRuleContext()) == 1 {
{
p.SetState(1025)
p.Match(ParserESCAPE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1026)
p.expr(0)
}
} else if p.HasError() { // JIM
goto errorExit
}
case 13:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(1029)
if !(p.Precpred(p.GetParserRuleContext(), 7)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 7)", ""))
goto errorExit
}
p.SetState(1034)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserISNULL_:
{
p.SetState(1030)
p.Match(ParserISNULL_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserNOTNULL_:
{
p.SetState(1031)
p.Match(ParserNOTNULL_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserNOT_:
{
p.SetState(1032)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1033)
p.Match(ParserNULL_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
case 14:
localctx = NewExprContext(p, _parentctx, _parentState)
p.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)
p.SetState(1036)
if !(p.Precpred(p.GetParserRuleContext(), 4)) {
p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 4)", ""))
goto errorExit
}
p.SetState(1038)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserNOT_ {
{
p.SetState(1037)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(1040)
p.Match(ParserIN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1079)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 134, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1041)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1051)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 129, p.GetParserRuleContext()) == 1 {
{
p.SetState(1042)
p.Select_stmt()
}
} else if p.HasError() { // JIM
goto errorExit
} else if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 129, p.GetParserRuleContext()) == 2 {
{
p.SetState(1043)
p.expr(0)
}
p.SetState(1048)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1044)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1045)
p.expr(0)
}
p.SetState(1050)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1053)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 2:
p.SetState(1057)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 130, p.GetParserRuleContext()) == 1 {
{
p.SetState(1054)
p.Schema_name()
}
{
p.SetState(1055)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1059)
p.Table_name()
}
case 3:
p.SetState(1063)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 131, p.GetParserRuleContext()) == 1 {
{
p.SetState(1060)
p.Schema_name()
}
{
p.SetState(1061)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1065)
p.Table_function_name()
}
{
p.SetState(1066)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1075)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if ((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&-33552632) != 0) || ((int64((_la-64)) & ^0x3f) == 0 && ((int64(1)<<(_la-64))&-1152921504606846977) != 0) || ((int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&4476578029606273023) != 0) {
{
p.SetState(1067)
p.expr(0)
}
p.SetState(1072)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1068)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1069)
p.expr(0)
}
p.SetState(1074)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
}
{
p.SetState(1077)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
}
p.SetState(1085)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 136, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.UnrollRecursionContexts(_parentctx)
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IRaise_functionContext is an interface to support dynamic dispatch.
type IRaise_functionContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
RAISE_() antlr.TerminalNode
OPEN_PAR() antlr.TerminalNode
CLOSE_PAR() antlr.TerminalNode
IGNORE_() antlr.TerminalNode
COMMA() antlr.TerminalNode
Error_message() IError_messageContext
ROLLBACK_() antlr.TerminalNode
ABORT_() antlr.TerminalNode
FAIL_() antlr.TerminalNode
// IsRaise_functionContext differentiates from other interfaces.
IsRaise_functionContext()
}
type Raise_functionContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyRaise_functionContext() *Raise_functionContext {
var p = new(Raise_functionContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_raise_function
return p
}
func InitEmptyRaise_functionContext(p *Raise_functionContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_raise_function
}
func (*Raise_functionContext) IsRaise_functionContext() {}
func NewRaise_functionContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Raise_functionContext {
var p = new(Raise_functionContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_raise_function
return p
}
func (s *Raise_functionContext) GetParser() antlr.Parser { return s.parser }
func (s *Raise_functionContext) RAISE_() antlr.TerminalNode {
return s.GetToken(ParserRAISE_, 0)
}
func (s *Raise_functionContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Raise_functionContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Raise_functionContext) IGNORE_() antlr.TerminalNode {
return s.GetToken(ParserIGNORE_, 0)
}
func (s *Raise_functionContext) COMMA() antlr.TerminalNode {
return s.GetToken(ParserCOMMA, 0)
}
func (s *Raise_functionContext) Error_message() IError_messageContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IError_messageContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IError_messageContext)
}
func (s *Raise_functionContext) ROLLBACK_() antlr.TerminalNode {
return s.GetToken(ParserROLLBACK_, 0)
}
func (s *Raise_functionContext) ABORT_() antlr.TerminalNode {
return s.GetToken(ParserABORT_, 0)
}
func (s *Raise_functionContext) FAIL_() antlr.TerminalNode {
return s.GetToken(ParserFAIL_, 0)
}
func (s *Raise_functionContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Raise_functionContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Raise_functionContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterRaise_function(s)
}
}
func (s *Raise_functionContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitRaise_function(s)
}
}
func (s *Raise_functionContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitRaise_function(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Raise_function() (localctx IRaise_functionContext) {
localctx = NewRaise_functionContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 66, ParserRULE_raise_function)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1086)
p.Match(ParserRAISE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1087)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1092)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserIGNORE_:
{
p.SetState(1088)
p.Match(ParserIGNORE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserABORT_, ParserFAIL_, ParserROLLBACK_:
{
p.SetState(1089)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserABORT_ || _la == ParserFAIL_ || _la == ParserROLLBACK_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
{
p.SetState(1090)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1091)
p.Error_message()
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
{
p.SetState(1094)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ILiteral_valueContext is an interface to support dynamic dispatch.
type ILiteral_valueContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
NUMERIC_LITERAL() antlr.TerminalNode
STRING_LITERAL() antlr.TerminalNode
BLOB_LITERAL() antlr.TerminalNode
NULL_() antlr.TerminalNode
TRUE_() antlr.TerminalNode
FALSE_() antlr.TerminalNode
CURRENT_TIME_() antlr.TerminalNode
CURRENT_DATE_() antlr.TerminalNode
CURRENT_TIMESTAMP_() antlr.TerminalNode
// IsLiteral_valueContext differentiates from other interfaces.
IsLiteral_valueContext()
}
type Literal_valueContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyLiteral_valueContext() *Literal_valueContext {
var p = new(Literal_valueContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_literal_value
return p
}
func InitEmptyLiteral_valueContext(p *Literal_valueContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_literal_value
}
func (*Literal_valueContext) IsLiteral_valueContext() {}
func NewLiteral_valueContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Literal_valueContext {
var p = new(Literal_valueContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_literal_value
return p
}
func (s *Literal_valueContext) GetParser() antlr.Parser { return s.parser }
func (s *Literal_valueContext) NUMERIC_LITERAL() antlr.TerminalNode {
return s.GetToken(ParserNUMERIC_LITERAL, 0)
}
func (s *Literal_valueContext) STRING_LITERAL() antlr.TerminalNode {
return s.GetToken(ParserSTRING_LITERAL, 0)
}
func (s *Literal_valueContext) BLOB_LITERAL() antlr.TerminalNode {
return s.GetToken(ParserBLOB_LITERAL, 0)
}
func (s *Literal_valueContext) NULL_() antlr.TerminalNode {
return s.GetToken(ParserNULL_, 0)
}
func (s *Literal_valueContext) TRUE_() antlr.TerminalNode {
return s.GetToken(ParserTRUE_, 0)
}
func (s *Literal_valueContext) FALSE_() antlr.TerminalNode {
return s.GetToken(ParserFALSE_, 0)
}
func (s *Literal_valueContext) CURRENT_TIME_() antlr.TerminalNode {
return s.GetToken(ParserCURRENT_TIME_, 0)
}
func (s *Literal_valueContext) CURRENT_DATE_() antlr.TerminalNode {
return s.GetToken(ParserCURRENT_DATE_, 0)
}
func (s *Literal_valueContext) CURRENT_TIMESTAMP_() antlr.TerminalNode {
return s.GetToken(ParserCURRENT_TIMESTAMP_, 0)
}
func (s *Literal_valueContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Literal_valueContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Literal_valueContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterLiteral_value(s)
}
}
func (s *Literal_valueContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitLiteral_value(s)
}
}
func (s *Literal_valueContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitLiteral_value(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Literal_value() (localctx ILiteral_valueContext) {
localctx = NewLiteral_valueContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 68, ParserRULE_literal_value)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1096)
_la = p.GetTokenStream().LA(1)
if !(((int64((_la-52)) & ^0x3f) == 0 && ((int64(1)<<(_la-52))&4503599627370503) != 0) || ((int64((_la-172)) & ^0x3f) == 0 && ((int64(1)<<(_la-172))&212995) != 0)) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IInsert_stmtContext is an interface to support dynamic dispatch.
type IInsert_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
INTO_() antlr.TerminalNode
Table_name() ITable_nameContext
INSERT_() antlr.TerminalNode
REPLACE_() antlr.TerminalNode
OR_() antlr.TerminalNode
DEFAULT_() antlr.TerminalNode
VALUES_() antlr.TerminalNode
With_clause() IWith_clauseContext
ROLLBACK_() antlr.TerminalNode
ABORT_() antlr.TerminalNode
FAIL_() antlr.TerminalNode
IGNORE_() antlr.TerminalNode
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
AS_() antlr.TerminalNode
Table_alias() ITable_aliasContext
AllOPEN_PAR() []antlr.TerminalNode
OPEN_PAR(i int) antlr.TerminalNode
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
AllCLOSE_PAR() []antlr.TerminalNode
CLOSE_PAR(i int) antlr.TerminalNode
Returning_clause() IReturning_clauseContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
Select_stmt() ISelect_stmtContext
Upsert_clause() IUpsert_clauseContext
// IsInsert_stmtContext differentiates from other interfaces.
IsInsert_stmtContext()
}
type Insert_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyInsert_stmtContext() *Insert_stmtContext {
var p = new(Insert_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_insert_stmt
return p
}
func InitEmptyInsert_stmtContext(p *Insert_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_insert_stmt
}
func (*Insert_stmtContext) IsInsert_stmtContext() {}
func NewInsert_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Insert_stmtContext {
var p = new(Insert_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_insert_stmt
return p
}
func (s *Insert_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Insert_stmtContext) INTO_() antlr.TerminalNode {
return s.GetToken(ParserINTO_, 0)
}
func (s *Insert_stmtContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Insert_stmtContext) INSERT_() antlr.TerminalNode {
return s.GetToken(ParserINSERT_, 0)
}
func (s *Insert_stmtContext) REPLACE_() antlr.TerminalNode {
return s.GetToken(ParserREPLACE_, 0)
}
func (s *Insert_stmtContext) OR_() antlr.TerminalNode {
return s.GetToken(ParserOR_, 0)
}
func (s *Insert_stmtContext) DEFAULT_() antlr.TerminalNode {
return s.GetToken(ParserDEFAULT_, 0)
}
func (s *Insert_stmtContext) VALUES_() antlr.TerminalNode {
return s.GetToken(ParserVALUES_, 0)
}
func (s *Insert_stmtContext) With_clause() IWith_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IWith_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IWith_clauseContext)
}
func (s *Insert_stmtContext) ROLLBACK_() antlr.TerminalNode {
return s.GetToken(ParserROLLBACK_, 0)
}
func (s *Insert_stmtContext) ABORT_() antlr.TerminalNode {
return s.GetToken(ParserABORT_, 0)
}
func (s *Insert_stmtContext) FAIL_() antlr.TerminalNode {
return s.GetToken(ParserFAIL_, 0)
}
func (s *Insert_stmtContext) IGNORE_() antlr.TerminalNode {
return s.GetToken(ParserIGNORE_, 0)
}
func (s *Insert_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Insert_stmtContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Insert_stmtContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *Insert_stmtContext) Table_alias() ITable_aliasContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_aliasContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_aliasContext)
}
func (s *Insert_stmtContext) AllOPEN_PAR() []antlr.TerminalNode {
return s.GetTokens(ParserOPEN_PAR)
}
func (s *Insert_stmtContext) OPEN_PAR(i int) antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, i)
}
func (s *Insert_stmtContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Insert_stmtContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Insert_stmtContext) AllCLOSE_PAR() []antlr.TerminalNode {
return s.GetTokens(ParserCLOSE_PAR)
}
func (s *Insert_stmtContext) CLOSE_PAR(i int) antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, i)
}
func (s *Insert_stmtContext) Returning_clause() IReturning_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IReturning_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IReturning_clauseContext)
}
func (s *Insert_stmtContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Insert_stmtContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Insert_stmtContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Insert_stmtContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Insert_stmtContext) Select_stmt() ISelect_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *Insert_stmtContext) Upsert_clause() IUpsert_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IUpsert_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IUpsert_clauseContext)
}
func (s *Insert_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Insert_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Insert_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterInsert_stmt(s)
}
}
func (s *Insert_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitInsert_stmt(s)
}
}
func (s *Insert_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitInsert_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Insert_stmt() (localctx IInsert_stmtContext) {
localctx = NewInsert_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 70, ParserRULE_insert_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(1099)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWITH_ {
{
p.SetState(1098)
p.With_clause()
}
}
p.SetState(1106)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 139, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1101)
p.Match(ParserINSERT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 2:
{
p.SetState(1102)
p.Match(ParserREPLACE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 3:
{
p.SetState(1103)
p.Match(ParserINSERT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1104)
p.Match(ParserOR_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1105)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserABORT_ || ((int64((_la-72)) & ^0x3f) == 0 && ((int64(1)<<(_la-72))&19140298416325121) != 0)) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
{
p.SetState(1108)
p.Match(ParserINTO_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1112)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 140, p.GetParserRuleContext()) == 1 {
{
p.SetState(1109)
p.Schema_name()
}
{
p.SetState(1110)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1114)
p.Table_name()
}
p.SetState(1117)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserAS_ {
{
p.SetState(1115)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1116)
p.Table_alias()
}
}
p.SetState(1130)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserOPEN_PAR {
{
p.SetState(1119)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1120)
p.Column_name()
}
p.SetState(1125)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1121)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1122)
p.Column_name()
}
p.SetState(1127)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(1128)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
p.SetState(1168)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserSELECT_, ParserVALUES_, ParserWITH_:
p.SetState(1161)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 147, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1132)
p.Match(ParserVALUES_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1133)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1134)
p.expr(0)
}
p.SetState(1139)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1135)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1136)
p.expr(0)
}
p.SetState(1141)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(1142)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1157)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1143)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1144)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1145)
p.expr(0)
}
p.SetState(1150)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1146)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1147)
p.expr(0)
}
p.SetState(1152)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(1153)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1159)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
case 2:
{
p.SetState(1160)
p.Select_stmt()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
p.SetState(1164)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserON_ {
{
p.SetState(1163)
p.Upsert_clause()
}
}
case ParserDEFAULT_:
{
p.SetState(1166)
p.Match(ParserDEFAULT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1167)
p.Match(ParserVALUES_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
p.SetState(1171)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserRETURNING_ {
{
p.SetState(1170)
p.Returning_clause()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IReturning_clauseContext is an interface to support dynamic dispatch.
type IReturning_clauseContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
RETURNING_() antlr.TerminalNode
AllResult_column() []IResult_columnContext
Result_column(i int) IResult_columnContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsReturning_clauseContext differentiates from other interfaces.
IsReturning_clauseContext()
}
type Returning_clauseContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyReturning_clauseContext() *Returning_clauseContext {
var p = new(Returning_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_returning_clause
return p
}
func InitEmptyReturning_clauseContext(p *Returning_clauseContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_returning_clause
}
func (*Returning_clauseContext) IsReturning_clauseContext() {}
func NewReturning_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Returning_clauseContext {
var p = new(Returning_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_returning_clause
return p
}
func (s *Returning_clauseContext) GetParser() antlr.Parser { return s.parser }
func (s *Returning_clauseContext) RETURNING_() antlr.TerminalNode {
return s.GetToken(ParserRETURNING_, 0)
}
func (s *Returning_clauseContext) AllResult_column() []IResult_columnContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IResult_columnContext); ok {
len++
}
}
tst := make([]IResult_columnContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IResult_columnContext); ok {
tst[i] = t.(IResult_columnContext)
i++
}
}
return tst
}
func (s *Returning_clauseContext) Result_column(i int) IResult_columnContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IResult_columnContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IResult_columnContext)
}
func (s *Returning_clauseContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Returning_clauseContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Returning_clauseContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Returning_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Returning_clauseContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterReturning_clause(s)
}
}
func (s *Returning_clauseContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitReturning_clause(s)
}
}
func (s *Returning_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitReturning_clause(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Returning_clause() (localctx IReturning_clauseContext) {
localctx = NewReturning_clauseContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 72, ParserRULE_returning_clause)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1173)
p.Match(ParserRETURNING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1174)
p.Result_column()
}
p.SetState(1179)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1175)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1176)
p.Result_column()
}
p.SetState(1181)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IUpsert_clauseContext is an interface to support dynamic dispatch.
type IUpsert_clauseContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ON_() antlr.TerminalNode
CONFLICT_() antlr.TerminalNode
DO_() antlr.TerminalNode
NOTHING_() antlr.TerminalNode
UPDATE_() antlr.TerminalNode
SET_() antlr.TerminalNode
OPEN_PAR() antlr.TerminalNode
AllIndexed_column() []IIndexed_columnContext
Indexed_column(i int) IIndexed_columnContext
CLOSE_PAR() antlr.TerminalNode
AllASSIGN() []antlr.TerminalNode
ASSIGN(i int) antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
AllWHERE_() []antlr.TerminalNode
WHERE_(i int) antlr.TerminalNode
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
AllColumn_name_list() []IColumn_name_listContext
Column_name_list(i int) IColumn_name_listContext
// IsUpsert_clauseContext differentiates from other interfaces.
IsUpsert_clauseContext()
}
type Upsert_clauseContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyUpsert_clauseContext() *Upsert_clauseContext {
var p = new(Upsert_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_upsert_clause
return p
}
func InitEmptyUpsert_clauseContext(p *Upsert_clauseContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_upsert_clause
}
func (*Upsert_clauseContext) IsUpsert_clauseContext() {}
func NewUpsert_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Upsert_clauseContext {
var p = new(Upsert_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_upsert_clause
return p
}
func (s *Upsert_clauseContext) GetParser() antlr.Parser { return s.parser }
func (s *Upsert_clauseContext) ON_() antlr.TerminalNode {
return s.GetToken(ParserON_, 0)
}
func (s *Upsert_clauseContext) CONFLICT_() antlr.TerminalNode {
return s.GetToken(ParserCONFLICT_, 0)
}
func (s *Upsert_clauseContext) DO_() antlr.TerminalNode {
return s.GetToken(ParserDO_, 0)
}
func (s *Upsert_clauseContext) NOTHING_() antlr.TerminalNode {
return s.GetToken(ParserNOTHING_, 0)
}
func (s *Upsert_clauseContext) UPDATE_() antlr.TerminalNode {
return s.GetToken(ParserUPDATE_, 0)
}
func (s *Upsert_clauseContext) SET_() antlr.TerminalNode {
return s.GetToken(ParserSET_, 0)
}
func (s *Upsert_clauseContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Upsert_clauseContext) AllIndexed_column() []IIndexed_columnContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IIndexed_columnContext); ok {
len++
}
}
tst := make([]IIndexed_columnContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IIndexed_columnContext); ok {
tst[i] = t.(IIndexed_columnContext)
i++
}
}
return tst
}
func (s *Upsert_clauseContext) Indexed_column(i int) IIndexed_columnContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IIndexed_columnContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IIndexed_columnContext)
}
func (s *Upsert_clauseContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Upsert_clauseContext) AllASSIGN() []antlr.TerminalNode {
return s.GetTokens(ParserASSIGN)
}
func (s *Upsert_clauseContext) ASSIGN(i int) antlr.TerminalNode {
return s.GetToken(ParserASSIGN, i)
}
func (s *Upsert_clauseContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Upsert_clauseContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Upsert_clauseContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Upsert_clauseContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Upsert_clauseContext) AllWHERE_() []antlr.TerminalNode {
return s.GetTokens(ParserWHERE_)
}
func (s *Upsert_clauseContext) WHERE_(i int) antlr.TerminalNode {
return s.GetToken(ParserWHERE_, i)
}
func (s *Upsert_clauseContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Upsert_clauseContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Upsert_clauseContext) AllColumn_name_list() []IColumn_name_listContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_name_listContext); ok {
len++
}
}
tst := make([]IColumn_name_listContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_name_listContext); ok {
tst[i] = t.(IColumn_name_listContext)
i++
}
}
return tst
}
func (s *Upsert_clauseContext) Column_name_list(i int) IColumn_name_listContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_name_listContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_name_listContext)
}
func (s *Upsert_clauseContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Upsert_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Upsert_clauseContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterUpsert_clause(s)
}
}
func (s *Upsert_clauseContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitUpsert_clause(s)
}
}
func (s *Upsert_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitUpsert_clause(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Upsert_clause() (localctx IUpsert_clauseContext) {
localctx = NewUpsert_clauseContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 74, ParserRULE_upsert_clause)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1182)
p.Match(ParserON_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1183)
p.Match(ParserCONFLICT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1198)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserOPEN_PAR {
{
p.SetState(1184)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1185)
p.Indexed_column()
}
p.SetState(1190)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1186)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1187)
p.Indexed_column()
}
p.SetState(1192)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(1193)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1196)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWHERE_ {
{
p.SetState(1194)
p.Match(ParserWHERE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1195)
p.expr(0)
}
}
}
{
p.SetState(1200)
p.Match(ParserDO_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1227)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserNOTHING_:
{
p.SetState(1201)
p.Match(ParserNOTHING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserUPDATE_:
{
p.SetState(1202)
p.Match(ParserUPDATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1203)
p.Match(ParserSET_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1206)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 155, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1204)
p.Column_name()
}
case 2:
{
p.SetState(1205)
p.Column_name_list()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
{
p.SetState(1208)
p.Match(ParserASSIGN)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1209)
p.expr(0)
}
p.SetState(1220)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1210)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1213)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 156, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1211)
p.Column_name()
}
case 2:
{
p.SetState(1212)
p.Column_name_list()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
{
p.SetState(1215)
p.Match(ParserASSIGN)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1216)
p.expr(0)
}
p.SetState(1222)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
p.SetState(1225)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWHERE_ {
{
p.SetState(1223)
p.Match(ParserWHERE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1224)
p.expr(0)
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IPragma_stmtContext is an interface to support dynamic dispatch.
type IPragma_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
PRAGMA_() antlr.TerminalNode
Pragma_name() IPragma_nameContext
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
ASSIGN() antlr.TerminalNode
Pragma_value() IPragma_valueContext
OPEN_PAR() antlr.TerminalNode
CLOSE_PAR() antlr.TerminalNode
// IsPragma_stmtContext differentiates from other interfaces.
IsPragma_stmtContext()
}
type Pragma_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyPragma_stmtContext() *Pragma_stmtContext {
var p = new(Pragma_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_pragma_stmt
return p
}
func InitEmptyPragma_stmtContext(p *Pragma_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_pragma_stmt
}
func (*Pragma_stmtContext) IsPragma_stmtContext() {}
func NewPragma_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Pragma_stmtContext {
var p = new(Pragma_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_pragma_stmt
return p
}
func (s *Pragma_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Pragma_stmtContext) PRAGMA_() antlr.TerminalNode {
return s.GetToken(ParserPRAGMA_, 0)
}
func (s *Pragma_stmtContext) Pragma_name() IPragma_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IPragma_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IPragma_nameContext)
}
func (s *Pragma_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Pragma_stmtContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Pragma_stmtContext) ASSIGN() antlr.TerminalNode {
return s.GetToken(ParserASSIGN, 0)
}
func (s *Pragma_stmtContext) Pragma_value() IPragma_valueContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IPragma_valueContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IPragma_valueContext)
}
func (s *Pragma_stmtContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Pragma_stmtContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Pragma_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Pragma_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Pragma_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterPragma_stmt(s)
}
}
func (s *Pragma_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitPragma_stmt(s)
}
}
func (s *Pragma_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitPragma_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Pragma_stmt() (localctx IPragma_stmtContext) {
localctx = NewPragma_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 76, ParserRULE_pragma_stmt)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1229)
p.Match(ParserPRAGMA_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1233)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 160, p.GetParserRuleContext()) == 1 {
{
p.SetState(1230)
p.Schema_name()
}
{
p.SetState(1231)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1235)
p.Pragma_name()
}
p.SetState(1242)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserASSIGN:
{
p.SetState(1236)
p.Match(ParserASSIGN)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1237)
p.Pragma_value()
}
case ParserOPEN_PAR:
{
p.SetState(1238)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1239)
p.Pragma_value()
}
{
p.SetState(1240)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserEOF, ParserSCOL, ParserALTER_, ParserANALYZE_, ParserATTACH_, ParserBEGIN_, ParserCOMMIT_, ParserCREATE_, ParserDELETE_, ParserDETACH_, ParserDROP_, ParserEND_, ParserEXPLAIN_, ParserINSERT_, ParserPRAGMA_, ParserREINDEX_, ParserRELEASE_, ParserREPLACE_, ParserROLLBACK_, ParserSAVEPOINT_, ParserSELECT_, ParserUPDATE_, ParserVACUUM_, ParserVALUES_, ParserWITH_:
default:
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IPragma_valueContext is an interface to support dynamic dispatch.
type IPragma_valueContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Signed_number() ISigned_numberContext
Name() INameContext
STRING_LITERAL() antlr.TerminalNode
// IsPragma_valueContext differentiates from other interfaces.
IsPragma_valueContext()
}
type Pragma_valueContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyPragma_valueContext() *Pragma_valueContext {
var p = new(Pragma_valueContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_pragma_value
return p
}
func InitEmptyPragma_valueContext(p *Pragma_valueContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_pragma_value
}
func (*Pragma_valueContext) IsPragma_valueContext() {}
func NewPragma_valueContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Pragma_valueContext {
var p = new(Pragma_valueContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_pragma_value
return p
}
func (s *Pragma_valueContext) GetParser() antlr.Parser { return s.parser }
func (s *Pragma_valueContext) Signed_number() ISigned_numberContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISigned_numberContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISigned_numberContext)
}
func (s *Pragma_valueContext) Name() INameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(INameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(INameContext)
}
func (s *Pragma_valueContext) STRING_LITERAL() antlr.TerminalNode {
return s.GetToken(ParserSTRING_LITERAL, 0)
}
func (s *Pragma_valueContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Pragma_valueContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Pragma_valueContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterPragma_value(s)
}
}
func (s *Pragma_valueContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitPragma_value(s)
}
}
func (s *Pragma_valueContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitPragma_value(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Pragma_value() (localctx IPragma_valueContext) {
localctx = NewPragma_valueContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 78, ParserRULE_pragma_value)
p.SetState(1247)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 162, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1244)
p.Signed_number()
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(1245)
p.Name()
}
case 3:
p.EnterOuterAlt(localctx, 3)
{
p.SetState(1246)
p.Match(ParserSTRING_LITERAL)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IReindex_stmtContext is an interface to support dynamic dispatch.
type IReindex_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
REINDEX_() antlr.TerminalNode
Collation_name() ICollation_nameContext
Table_name() ITable_nameContext
Index_name() IIndex_nameContext
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
// IsReindex_stmtContext differentiates from other interfaces.
IsReindex_stmtContext()
}
type Reindex_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyReindex_stmtContext() *Reindex_stmtContext {
var p = new(Reindex_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_reindex_stmt
return p
}
func InitEmptyReindex_stmtContext(p *Reindex_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_reindex_stmt
}
func (*Reindex_stmtContext) IsReindex_stmtContext() {}
func NewReindex_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Reindex_stmtContext {
var p = new(Reindex_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_reindex_stmt
return p
}
func (s *Reindex_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Reindex_stmtContext) REINDEX_() antlr.TerminalNode {
return s.GetToken(ParserREINDEX_, 0)
}
func (s *Reindex_stmtContext) Collation_name() ICollation_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICollation_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICollation_nameContext)
}
func (s *Reindex_stmtContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Reindex_stmtContext) Index_name() IIndex_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IIndex_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IIndex_nameContext)
}
func (s *Reindex_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Reindex_stmtContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Reindex_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Reindex_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Reindex_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterReindex_stmt(s)
}
}
func (s *Reindex_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitReindex_stmt(s)
}
}
func (s *Reindex_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitReindex_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Reindex_stmt() (localctx IReindex_stmtContext) {
localctx = NewReindex_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 80, ParserRULE_reindex_stmt)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1249)
p.Match(ParserREINDEX_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1260)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 165, p.GetParserRuleContext()) == 1 {
{
p.SetState(1250)
p.Collation_name()
}
} else if p.HasError() { // JIM
goto errorExit
} else if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 165, p.GetParserRuleContext()) == 2 {
p.SetState(1254)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 163, p.GetParserRuleContext()) == 1 {
{
p.SetState(1251)
p.Schema_name()
}
{
p.SetState(1252)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(1258)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 164, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1256)
p.Table_name()
}
case 2:
{
p.SetState(1257)
p.Index_name()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
} else if p.HasError() { // JIM
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ISelect_stmtContext is an interface to support dynamic dispatch.
type ISelect_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
AllSelect_core() []ISelect_coreContext
Select_core(i int) ISelect_coreContext
Common_table_stmt() ICommon_table_stmtContext
AllCompound_operator() []ICompound_operatorContext
Compound_operator(i int) ICompound_operatorContext
Order_by_stmt() IOrder_by_stmtContext
Limit_stmt() ILimit_stmtContext
// IsSelect_stmtContext differentiates from other interfaces.
IsSelect_stmtContext()
}
type Select_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptySelect_stmtContext() *Select_stmtContext {
var p = new(Select_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_select_stmt
return p
}
func InitEmptySelect_stmtContext(p *Select_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_select_stmt
}
func (*Select_stmtContext) IsSelect_stmtContext() {}
func NewSelect_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Select_stmtContext {
var p = new(Select_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_select_stmt
return p
}
func (s *Select_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Select_stmtContext) AllSelect_core() []ISelect_coreContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ISelect_coreContext); ok {
len++
}
}
tst := make([]ISelect_coreContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ISelect_coreContext); ok {
tst[i] = t.(ISelect_coreContext)
i++
}
}
return tst
}
func (s *Select_stmtContext) Select_core(i int) ISelect_coreContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_coreContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ISelect_coreContext)
}
func (s *Select_stmtContext) Common_table_stmt() ICommon_table_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICommon_table_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICommon_table_stmtContext)
}
func (s *Select_stmtContext) AllCompound_operator() []ICompound_operatorContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ICompound_operatorContext); ok {
len++
}
}
tst := make([]ICompound_operatorContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ICompound_operatorContext); ok {
tst[i] = t.(ICompound_operatorContext)
i++
}
}
return tst
}
func (s *Select_stmtContext) Compound_operator(i int) ICompound_operatorContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICompound_operatorContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ICompound_operatorContext)
}
func (s *Select_stmtContext) Order_by_stmt() IOrder_by_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOrder_by_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IOrder_by_stmtContext)
}
func (s *Select_stmtContext) Limit_stmt() ILimit_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ILimit_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ILimit_stmtContext)
}
func (s *Select_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Select_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Select_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterSelect_stmt(s)
}
}
func (s *Select_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitSelect_stmt(s)
}
}
func (s *Select_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitSelect_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Select_stmt() (localctx ISelect_stmtContext) {
localctx = NewSelect_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 82, ParserRULE_select_stmt)
var _la int
var _alt int
p.EnterOuterAlt(localctx, 1)
p.SetState(1263)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWITH_ {
{
p.SetState(1262)
p.Common_table_stmt()
}
}
{
p.SetState(1265)
p.Select_core()
}
p.SetState(1271)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 167, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
for _alt != 2 && _alt != antlr.ATNInvalidAltNumber {
if _alt == 1 {
{
p.SetState(1266)
p.Compound_operator()
}
{
p.SetState(1267)
p.Select_core()
}
}
p.SetState(1273)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 167, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
}
p.SetState(1275)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserORDER_ {
{
p.SetState(1274)
p.Order_by_stmt()
}
}
p.SetState(1278)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserLIMIT_ {
{
p.SetState(1277)
p.Limit_stmt()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IJoin_clauseContext is an interface to support dynamic dispatch.
type IJoin_clauseContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
AllTable_or_subquery() []ITable_or_subqueryContext
Table_or_subquery(i int) ITable_or_subqueryContext
AllJoin_operator() []IJoin_operatorContext
Join_operator(i int) IJoin_operatorContext
AllJoin_constraint() []IJoin_constraintContext
Join_constraint(i int) IJoin_constraintContext
// IsJoin_clauseContext differentiates from other interfaces.
IsJoin_clauseContext()
}
type Join_clauseContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyJoin_clauseContext() *Join_clauseContext {
var p = new(Join_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_join_clause
return p
}
func InitEmptyJoin_clauseContext(p *Join_clauseContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_join_clause
}
func (*Join_clauseContext) IsJoin_clauseContext() {}
func NewJoin_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Join_clauseContext {
var p = new(Join_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_join_clause
return p
}
func (s *Join_clauseContext) GetParser() antlr.Parser { return s.parser }
func (s *Join_clauseContext) AllTable_or_subquery() []ITable_or_subqueryContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ITable_or_subqueryContext); ok {
len++
}
}
tst := make([]ITable_or_subqueryContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ITable_or_subqueryContext); ok {
tst[i] = t.(ITable_or_subqueryContext)
i++
}
}
return tst
}
func (s *Join_clauseContext) Table_or_subquery(i int) ITable_or_subqueryContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_or_subqueryContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ITable_or_subqueryContext)
}
func (s *Join_clauseContext) AllJoin_operator() []IJoin_operatorContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IJoin_operatorContext); ok {
len++
}
}
tst := make([]IJoin_operatorContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IJoin_operatorContext); ok {
tst[i] = t.(IJoin_operatorContext)
i++
}
}
return tst
}
func (s *Join_clauseContext) Join_operator(i int) IJoin_operatorContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IJoin_operatorContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IJoin_operatorContext)
}
func (s *Join_clauseContext) AllJoin_constraint() []IJoin_constraintContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IJoin_constraintContext); ok {
len++
}
}
tst := make([]IJoin_constraintContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IJoin_constraintContext); ok {
tst[i] = t.(IJoin_constraintContext)
i++
}
}
return tst
}
func (s *Join_clauseContext) Join_constraint(i int) IJoin_constraintContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IJoin_constraintContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IJoin_constraintContext)
}
func (s *Join_clauseContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Join_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Join_clauseContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterJoin_clause(s)
}
}
func (s *Join_clauseContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitJoin_clause(s)
}
}
func (s *Join_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitJoin_clause(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Join_clause() (localctx IJoin_clauseContext) {
localctx = NewJoin_clauseContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 84, ParserRULE_join_clause)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1280)
p.Table_or_subquery()
}
p.SetState(1288)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA || _la == ParserCROSS_ || ((int64((_la-87)) & ^0x3f) == 0 && ((int64(1)<<(_la-87))&8833) != 0) {
{
p.SetState(1281)
p.Join_operator()
}
{
p.SetState(1282)
p.Table_or_subquery()
}
p.SetState(1284)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 170, p.GetParserRuleContext()) == 1 {
{
p.SetState(1283)
p.Join_constraint()
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(1290)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ISelect_coreContext is an interface to support dynamic dispatch.
type ISelect_coreContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
SELECT_() antlr.TerminalNode
AllResult_column() []IResult_columnContext
Result_column(i int) IResult_columnContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
FROM_() antlr.TerminalNode
WHERE_() antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
GROUP_() antlr.TerminalNode
BY_() antlr.TerminalNode
WINDOW_() antlr.TerminalNode
AllWindow_name() []IWindow_nameContext
Window_name(i int) IWindow_nameContext
AllAS_() []antlr.TerminalNode
AS_(i int) antlr.TerminalNode
AllWindow_defn() []IWindow_defnContext
Window_defn(i int) IWindow_defnContext
DISTINCT_() antlr.TerminalNode
ALL_() antlr.TerminalNode
AllTable_or_subquery() []ITable_or_subqueryContext
Table_or_subquery(i int) ITable_or_subqueryContext
Join_clause() IJoin_clauseContext
HAVING_() antlr.TerminalNode
VALUES_() antlr.TerminalNode
AllOPEN_PAR() []antlr.TerminalNode
OPEN_PAR(i int) antlr.TerminalNode
AllCLOSE_PAR() []antlr.TerminalNode
CLOSE_PAR(i int) antlr.TerminalNode
// IsSelect_coreContext differentiates from other interfaces.
IsSelect_coreContext()
}
type Select_coreContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptySelect_coreContext() *Select_coreContext {
var p = new(Select_coreContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_select_core
return p
}
func InitEmptySelect_coreContext(p *Select_coreContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_select_core
}
func (*Select_coreContext) IsSelect_coreContext() {}
func NewSelect_coreContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Select_coreContext {
var p = new(Select_coreContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_select_core
return p
}
func (s *Select_coreContext) GetParser() antlr.Parser { return s.parser }
func (s *Select_coreContext) SELECT_() antlr.TerminalNode {
return s.GetToken(ParserSELECT_, 0)
}
func (s *Select_coreContext) AllResult_column() []IResult_columnContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IResult_columnContext); ok {
len++
}
}
tst := make([]IResult_columnContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IResult_columnContext); ok {
tst[i] = t.(IResult_columnContext)
i++
}
}
return tst
}
func (s *Select_coreContext) Result_column(i int) IResult_columnContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IResult_columnContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IResult_columnContext)
}
func (s *Select_coreContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Select_coreContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Select_coreContext) FROM_() antlr.TerminalNode {
return s.GetToken(ParserFROM_, 0)
}
func (s *Select_coreContext) WHERE_() antlr.TerminalNode {
return s.GetToken(ParserWHERE_, 0)
}
func (s *Select_coreContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Select_coreContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Select_coreContext) GROUP_() antlr.TerminalNode {
return s.GetToken(ParserGROUP_, 0)
}
func (s *Select_coreContext) BY_() antlr.TerminalNode {
return s.GetToken(ParserBY_, 0)
}
func (s *Select_coreContext) WINDOW_() antlr.TerminalNode {
return s.GetToken(ParserWINDOW_, 0)
}
func (s *Select_coreContext) AllWindow_name() []IWindow_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IWindow_nameContext); ok {
len++
}
}
tst := make([]IWindow_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IWindow_nameContext); ok {
tst[i] = t.(IWindow_nameContext)
i++
}
}
return tst
}
func (s *Select_coreContext) Window_name(i int) IWindow_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IWindow_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IWindow_nameContext)
}
func (s *Select_coreContext) AllAS_() []antlr.TerminalNode {
return s.GetTokens(ParserAS_)
}
func (s *Select_coreContext) AS_(i int) antlr.TerminalNode {
return s.GetToken(ParserAS_, i)
}
func (s *Select_coreContext) AllWindow_defn() []IWindow_defnContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IWindow_defnContext); ok {
len++
}
}
tst := make([]IWindow_defnContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IWindow_defnContext); ok {
tst[i] = t.(IWindow_defnContext)
i++
}
}
return tst
}
func (s *Select_coreContext) Window_defn(i int) IWindow_defnContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IWindow_defnContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IWindow_defnContext)
}
func (s *Select_coreContext) DISTINCT_() antlr.TerminalNode {
return s.GetToken(ParserDISTINCT_, 0)
}
func (s *Select_coreContext) ALL_() antlr.TerminalNode {
return s.GetToken(ParserALL_, 0)
}
func (s *Select_coreContext) AllTable_or_subquery() []ITable_or_subqueryContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ITable_or_subqueryContext); ok {
len++
}
}
tst := make([]ITable_or_subqueryContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ITable_or_subqueryContext); ok {
tst[i] = t.(ITable_or_subqueryContext)
i++
}
}
return tst
}
func (s *Select_coreContext) Table_or_subquery(i int) ITable_or_subqueryContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_or_subqueryContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ITable_or_subqueryContext)
}
func (s *Select_coreContext) Join_clause() IJoin_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IJoin_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IJoin_clauseContext)
}
func (s *Select_coreContext) HAVING_() antlr.TerminalNode {
return s.GetToken(ParserHAVING_, 0)
}
func (s *Select_coreContext) VALUES_() antlr.TerminalNode {
return s.GetToken(ParserVALUES_, 0)
}
func (s *Select_coreContext) AllOPEN_PAR() []antlr.TerminalNode {
return s.GetTokens(ParserOPEN_PAR)
}
func (s *Select_coreContext) OPEN_PAR(i int) antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, i)
}
func (s *Select_coreContext) AllCLOSE_PAR() []antlr.TerminalNode {
return s.GetTokens(ParserCLOSE_PAR)
}
func (s *Select_coreContext) CLOSE_PAR(i int) antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, i)
}
func (s *Select_coreContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Select_coreContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Select_coreContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterSelect_core(s)
}
}
func (s *Select_coreContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitSelect_core(s)
}
}
func (s *Select_coreContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitSelect_core(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Select_core() (localctx ISelect_coreContext) {
localctx = NewSelect_coreContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 86, ParserRULE_select_core)
var _la int
p.SetState(1381)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserSELECT_:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1291)
p.Match(ParserSELECT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1293)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 172, p.GetParserRuleContext()) == 1 {
{
p.SetState(1292)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserALL_ || _la == ParserDISTINCT_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1295)
p.Result_column()
}
p.SetState(1300)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1296)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1297)
p.Result_column()
}
p.SetState(1302)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
p.SetState(1315)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserFROM_ {
{
p.SetState(1303)
p.Match(ParserFROM_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1313)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 175, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1304)
p.Table_or_subquery()
}
p.SetState(1309)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1305)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1306)
p.Table_or_subquery()
}
p.SetState(1311)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
case 2:
{
p.SetState(1312)
p.Join_clause()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
}
p.SetState(1319)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWHERE_ {
{
p.SetState(1317)
p.Match(ParserWHERE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1318)
p.expr(0)
}
}
p.SetState(1335)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserGROUP_ {
{
p.SetState(1321)
p.Match(ParserGROUP_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1322)
p.Match(ParserBY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1323)
p.expr(0)
}
p.SetState(1328)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1324)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1325)
p.expr(0)
}
p.SetState(1330)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
p.SetState(1333)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserHAVING_ {
{
p.SetState(1331)
p.Match(ParserHAVING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1332)
p.expr(0)
}
}
}
p.SetState(1351)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWINDOW_ {
{
p.SetState(1337)
p.Match(ParserWINDOW_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1338)
p.Window_name()
}
{
p.SetState(1339)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1340)
p.Window_defn()
}
p.SetState(1348)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1341)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1342)
p.Window_name()
}
{
p.SetState(1343)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1344)
p.Window_defn()
}
p.SetState(1350)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
}
case ParserVALUES_:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(1353)
p.Match(ParserVALUES_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1354)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1355)
p.expr(0)
}
p.SetState(1360)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1356)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1357)
p.expr(0)
}
p.SetState(1362)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(1363)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1378)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1364)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1365)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1366)
p.expr(0)
}
p.SetState(1371)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1367)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1368)
p.expr(0)
}
p.SetState(1373)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(1374)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1380)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IFactored_select_stmtContext is an interface to support dynamic dispatch.
type IFactored_select_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Select_stmt() ISelect_stmtContext
// IsFactored_select_stmtContext differentiates from other interfaces.
IsFactored_select_stmtContext()
}
type Factored_select_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyFactored_select_stmtContext() *Factored_select_stmtContext {
var p = new(Factored_select_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_factored_select_stmt
return p
}
func InitEmptyFactored_select_stmtContext(p *Factored_select_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_factored_select_stmt
}
func (*Factored_select_stmtContext) IsFactored_select_stmtContext() {}
func NewFactored_select_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Factored_select_stmtContext {
var p = new(Factored_select_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_factored_select_stmt
return p
}
func (s *Factored_select_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Factored_select_stmtContext) Select_stmt() ISelect_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *Factored_select_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Factored_select_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Factored_select_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterFactored_select_stmt(s)
}
}
func (s *Factored_select_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitFactored_select_stmt(s)
}
}
func (s *Factored_select_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitFactored_select_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Factored_select_stmt() (localctx IFactored_select_stmtContext) {
localctx = NewFactored_select_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 88, ParserRULE_factored_select_stmt)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1383)
p.Select_stmt()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ISimple_select_stmtContext is an interface to support dynamic dispatch.
type ISimple_select_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Select_core() ISelect_coreContext
Common_table_stmt() ICommon_table_stmtContext
Order_by_stmt() IOrder_by_stmtContext
Limit_stmt() ILimit_stmtContext
// IsSimple_select_stmtContext differentiates from other interfaces.
IsSimple_select_stmtContext()
}
type Simple_select_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptySimple_select_stmtContext() *Simple_select_stmtContext {
var p = new(Simple_select_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_simple_select_stmt
return p
}
func InitEmptySimple_select_stmtContext(p *Simple_select_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_simple_select_stmt
}
func (*Simple_select_stmtContext) IsSimple_select_stmtContext() {}
func NewSimple_select_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Simple_select_stmtContext {
var p = new(Simple_select_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_simple_select_stmt
return p
}
func (s *Simple_select_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Simple_select_stmtContext) Select_core() ISelect_coreContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_coreContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISelect_coreContext)
}
func (s *Simple_select_stmtContext) Common_table_stmt() ICommon_table_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICommon_table_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICommon_table_stmtContext)
}
func (s *Simple_select_stmtContext) Order_by_stmt() IOrder_by_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOrder_by_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IOrder_by_stmtContext)
}
func (s *Simple_select_stmtContext) Limit_stmt() ILimit_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ILimit_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ILimit_stmtContext)
}
func (s *Simple_select_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Simple_select_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Simple_select_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterSimple_select_stmt(s)
}
}
func (s *Simple_select_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitSimple_select_stmt(s)
}
}
func (s *Simple_select_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitSimple_select_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Simple_select_stmt() (localctx ISimple_select_stmtContext) {
localctx = NewSimple_select_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 90, ParserRULE_simple_select_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(1386)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWITH_ {
{
p.SetState(1385)
p.Common_table_stmt()
}
}
{
p.SetState(1388)
p.Select_core()
}
p.SetState(1390)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserORDER_ {
{
p.SetState(1389)
p.Order_by_stmt()
}
}
p.SetState(1393)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserLIMIT_ {
{
p.SetState(1392)
p.Limit_stmt()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICompound_select_stmtContext is an interface to support dynamic dispatch.
type ICompound_select_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
AllSelect_core() []ISelect_coreContext
Select_core(i int) ISelect_coreContext
Common_table_stmt() ICommon_table_stmtContext
Order_by_stmt() IOrder_by_stmtContext
Limit_stmt() ILimit_stmtContext
AllUNION_() []antlr.TerminalNode
UNION_(i int) antlr.TerminalNode
AllINTERSECT_() []antlr.TerminalNode
INTERSECT_(i int) antlr.TerminalNode
AllEXCEPT_() []antlr.TerminalNode
EXCEPT_(i int) antlr.TerminalNode
AllALL_() []antlr.TerminalNode
ALL_(i int) antlr.TerminalNode
// IsCompound_select_stmtContext differentiates from other interfaces.
IsCompound_select_stmtContext()
}
type Compound_select_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyCompound_select_stmtContext() *Compound_select_stmtContext {
var p = new(Compound_select_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_compound_select_stmt
return p
}
func InitEmptyCompound_select_stmtContext(p *Compound_select_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_compound_select_stmt
}
func (*Compound_select_stmtContext) IsCompound_select_stmtContext() {}
func NewCompound_select_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Compound_select_stmtContext {
var p = new(Compound_select_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_compound_select_stmt
return p
}
func (s *Compound_select_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Compound_select_stmtContext) AllSelect_core() []ISelect_coreContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ISelect_coreContext); ok {
len++
}
}
tst := make([]ISelect_coreContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ISelect_coreContext); ok {
tst[i] = t.(ISelect_coreContext)
i++
}
}
return tst
}
func (s *Compound_select_stmtContext) Select_core(i int) ISelect_coreContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_coreContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ISelect_coreContext)
}
func (s *Compound_select_stmtContext) Common_table_stmt() ICommon_table_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICommon_table_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICommon_table_stmtContext)
}
func (s *Compound_select_stmtContext) Order_by_stmt() IOrder_by_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOrder_by_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IOrder_by_stmtContext)
}
func (s *Compound_select_stmtContext) Limit_stmt() ILimit_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ILimit_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ILimit_stmtContext)
}
func (s *Compound_select_stmtContext) AllUNION_() []antlr.TerminalNode {
return s.GetTokens(ParserUNION_)
}
func (s *Compound_select_stmtContext) UNION_(i int) antlr.TerminalNode {
return s.GetToken(ParserUNION_, i)
}
func (s *Compound_select_stmtContext) AllINTERSECT_() []antlr.TerminalNode {
return s.GetTokens(ParserINTERSECT_)
}
func (s *Compound_select_stmtContext) INTERSECT_(i int) antlr.TerminalNode {
return s.GetToken(ParserINTERSECT_, i)
}
func (s *Compound_select_stmtContext) AllEXCEPT_() []antlr.TerminalNode {
return s.GetTokens(ParserEXCEPT_)
}
func (s *Compound_select_stmtContext) EXCEPT_(i int) antlr.TerminalNode {
return s.GetToken(ParserEXCEPT_, i)
}
func (s *Compound_select_stmtContext) AllALL_() []antlr.TerminalNode {
return s.GetTokens(ParserALL_)
}
func (s *Compound_select_stmtContext) ALL_(i int) antlr.TerminalNode {
return s.GetToken(ParserALL_, i)
}
func (s *Compound_select_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Compound_select_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Compound_select_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCompound_select_stmt(s)
}
}
func (s *Compound_select_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCompound_select_stmt(s)
}
}
func (s *Compound_select_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCompound_select_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Compound_select_stmt() (localctx ICompound_select_stmtContext) {
localctx = NewCompound_select_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 92, ParserRULE_compound_select_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(1396)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWITH_ {
{
p.SetState(1395)
p.Common_table_stmt()
}
}
{
p.SetState(1398)
p.Select_core()
}
p.SetState(1408)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for ok := true; ok; ok = _la == ParserEXCEPT_ || _la == ParserINTERSECT_ || _la == ParserUNION_ {
p.SetState(1405)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserUNION_:
{
p.SetState(1399)
p.Match(ParserUNION_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1401)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserALL_ {
{
p.SetState(1400)
p.Match(ParserALL_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
case ParserINTERSECT_:
{
p.SetState(1403)
p.Match(ParserINTERSECT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserEXCEPT_:
{
p.SetState(1404)
p.Match(ParserEXCEPT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
{
p.SetState(1407)
p.Select_core()
}
p.SetState(1410)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
p.SetState(1413)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserORDER_ {
{
p.SetState(1412)
p.Order_by_stmt()
}
}
p.SetState(1416)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserLIMIT_ {
{
p.SetState(1415)
p.Limit_stmt()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ITable_or_subqueryContext is an interface to support dynamic dispatch.
type ITable_or_subqueryContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Table_name() ITable_nameContext
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
Table_alias() ITable_aliasContext
INDEXED_() antlr.TerminalNode
BY_() antlr.TerminalNode
Index_name() IIndex_nameContext
NOT_() antlr.TerminalNode
AS_() antlr.TerminalNode
Table_function_name() ITable_function_nameContext
OPEN_PAR() antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
CLOSE_PAR() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
AllTable_or_subquery() []ITable_or_subqueryContext
Table_or_subquery(i int) ITable_or_subqueryContext
Join_clause() IJoin_clauseContext
Select_stmt() ISelect_stmtContext
// IsTable_or_subqueryContext differentiates from other interfaces.
IsTable_or_subqueryContext()
}
type Table_or_subqueryContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyTable_or_subqueryContext() *Table_or_subqueryContext {
var p = new(Table_or_subqueryContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_or_subquery
return p
}
func InitEmptyTable_or_subqueryContext(p *Table_or_subqueryContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_or_subquery
}
func (*Table_or_subqueryContext) IsTable_or_subqueryContext() {}
func NewTable_or_subqueryContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_or_subqueryContext {
var p = new(Table_or_subqueryContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_table_or_subquery
return p
}
func (s *Table_or_subqueryContext) GetParser() antlr.Parser { return s.parser }
func (s *Table_or_subqueryContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Table_or_subqueryContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Table_or_subqueryContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Table_or_subqueryContext) Table_alias() ITable_aliasContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_aliasContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_aliasContext)
}
func (s *Table_or_subqueryContext) INDEXED_() antlr.TerminalNode {
return s.GetToken(ParserINDEXED_, 0)
}
func (s *Table_or_subqueryContext) BY_() antlr.TerminalNode {
return s.GetToken(ParserBY_, 0)
}
func (s *Table_or_subqueryContext) Index_name() IIndex_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IIndex_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IIndex_nameContext)
}
func (s *Table_or_subqueryContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *Table_or_subqueryContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *Table_or_subqueryContext) Table_function_name() ITable_function_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_function_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_function_nameContext)
}
func (s *Table_or_subqueryContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Table_or_subqueryContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Table_or_subqueryContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Table_or_subqueryContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Table_or_subqueryContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Table_or_subqueryContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Table_or_subqueryContext) AllTable_or_subquery() []ITable_or_subqueryContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ITable_or_subqueryContext); ok {
len++
}
}
tst := make([]ITable_or_subqueryContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ITable_or_subqueryContext); ok {
tst[i] = t.(ITable_or_subqueryContext)
i++
}
}
return tst
}
func (s *Table_or_subqueryContext) Table_or_subquery(i int) ITable_or_subqueryContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_or_subqueryContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ITable_or_subqueryContext)
}
func (s *Table_or_subqueryContext) Join_clause() IJoin_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IJoin_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IJoin_clauseContext)
}
func (s *Table_or_subqueryContext) Select_stmt() ISelect_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *Table_or_subqueryContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Table_or_subqueryContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Table_or_subqueryContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterTable_or_subquery(s)
}
}
func (s *Table_or_subqueryContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitTable_or_subquery(s)
}
}
func (s *Table_or_subqueryContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitTable_or_subquery(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Table_or_subquery() (localctx ITable_or_subqueryContext) {
localctx = NewTable_or_subqueryContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 94, ParserRULE_table_or_subquery)
var _la int
p.SetState(1482)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 208, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
p.SetState(1421)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 196, p.GetParserRuleContext()) == 1 {
{
p.SetState(1418)
p.Schema_name()
}
{
p.SetState(1419)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1423)
p.Table_name()
}
p.SetState(1428)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 198, p.GetParserRuleContext()) == 1 {
p.SetState(1425)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 197, p.GetParserRuleContext()) == 1 {
{
p.SetState(1424)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1427)
p.Table_alias()
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(1435)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserINDEXED_:
{
p.SetState(1430)
p.Match(ParserINDEXED_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1431)
p.Match(ParserBY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1432)
p.Index_name()
}
case ParserNOT_:
{
p.SetState(1433)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1434)
p.Match(ParserINDEXED_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserEOF, ParserSCOL, ParserCLOSE_PAR, ParserCOMMA, ParserALTER_, ParserANALYZE_, ParserATTACH_, ParserBEGIN_, ParserCOMMIT_, ParserCREATE_, ParserCROSS_, ParserDELETE_, ParserDETACH_, ParserDROP_, ParserEND_, ParserEXCEPT_, ParserEXPLAIN_, ParserGROUP_, ParserINNER_, ParserINSERT_, ParserINTERSECT_, ParserJOIN_, ParserLEFT_, ParserLIMIT_, ParserNATURAL_, ParserON_, ParserORDER_, ParserPRAGMA_, ParserREINDEX_, ParserRELEASE_, ParserREPLACE_, ParserRETURNING_, ParserROLLBACK_, ParserSAVEPOINT_, ParserSELECT_, ParserUNION_, ParserUPDATE_, ParserUSING_, ParserVACUUM_, ParserVALUES_, ParserWHERE_, ParserWITH_, ParserWINDOW_:
default:
}
case 2:
p.EnterOuterAlt(localctx, 2)
p.SetState(1440)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 200, p.GetParserRuleContext()) == 1 {
{
p.SetState(1437)
p.Schema_name()
}
{
p.SetState(1438)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1442)
p.Table_function_name()
}
{
p.SetState(1443)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1444)
p.expr(0)
}
p.SetState(1449)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1445)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1446)
p.expr(0)
}
p.SetState(1451)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(1452)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1457)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 203, p.GetParserRuleContext()) == 1 {
p.SetState(1454)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 202, p.GetParserRuleContext()) == 1 {
{
p.SetState(1453)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1456)
p.Table_alias()
}
} else if p.HasError() { // JIM
goto errorExit
}
case 3:
p.EnterOuterAlt(localctx, 3)
{
p.SetState(1459)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1469)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 205, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1460)
p.Table_or_subquery()
}
p.SetState(1465)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1461)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1462)
p.Table_or_subquery()
}
p.SetState(1467)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
case 2:
{
p.SetState(1468)
p.Join_clause()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
{
p.SetState(1471)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 4:
p.EnterOuterAlt(localctx, 4)
{
p.SetState(1473)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1474)
p.Select_stmt()
}
{
p.SetState(1475)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1480)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 207, p.GetParserRuleContext()) == 1 {
p.SetState(1477)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 206, p.GetParserRuleContext()) == 1 {
{
p.SetState(1476)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1479)
p.Table_alias()
}
} else if p.HasError() { // JIM
goto errorExit
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IResult_columnContext is an interface to support dynamic dispatch.
type IResult_columnContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
STAR() antlr.TerminalNode
Table_name() ITable_nameContext
DOT() antlr.TerminalNode
Expr() IExprContext
Column_alias() IColumn_aliasContext
AS_() antlr.TerminalNode
// IsResult_columnContext differentiates from other interfaces.
IsResult_columnContext()
}
type Result_columnContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyResult_columnContext() *Result_columnContext {
var p = new(Result_columnContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_result_column
return p
}
func InitEmptyResult_columnContext(p *Result_columnContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_result_column
}
func (*Result_columnContext) IsResult_columnContext() {}
func NewResult_columnContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Result_columnContext {
var p = new(Result_columnContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_result_column
return p
}
func (s *Result_columnContext) GetParser() antlr.Parser { return s.parser }
func (s *Result_columnContext) STAR() antlr.TerminalNode {
return s.GetToken(ParserSTAR, 0)
}
func (s *Result_columnContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Result_columnContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Result_columnContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Result_columnContext) Column_alias() IColumn_aliasContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_aliasContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IColumn_aliasContext)
}
func (s *Result_columnContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *Result_columnContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Result_columnContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Result_columnContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterResult_column(s)
}
}
func (s *Result_columnContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitResult_column(s)
}
}
func (s *Result_columnContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitResult_column(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Result_column() (localctx IResult_columnContext) {
localctx = NewResult_columnContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 96, ParserRULE_result_column)
var _la int
p.SetState(1496)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 211, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1484)
p.Match(ParserSTAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(1485)
p.Table_name()
}
{
p.SetState(1486)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1487)
p.Match(ParserSTAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 3:
p.EnterOuterAlt(localctx, 3)
{
p.SetState(1489)
p.expr(0)
}
p.SetState(1494)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserAS_ || _la == ParserIDENTIFIER || _la == ParserSTRING_LITERAL {
p.SetState(1491)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserAS_ {
{
p.SetState(1490)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
{
p.SetState(1493)
p.Column_alias()
}
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IJoin_operatorContext is an interface to support dynamic dispatch.
type IJoin_operatorContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
COMMA() antlr.TerminalNode
JOIN_() antlr.TerminalNode
NATURAL_() antlr.TerminalNode
LEFT_() antlr.TerminalNode
INNER_() antlr.TerminalNode
CROSS_() antlr.TerminalNode
OUTER_() antlr.TerminalNode
// IsJoin_operatorContext differentiates from other interfaces.
IsJoin_operatorContext()
}
type Join_operatorContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyJoin_operatorContext() *Join_operatorContext {
var p = new(Join_operatorContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_join_operator
return p
}
func InitEmptyJoin_operatorContext(p *Join_operatorContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_join_operator
}
func (*Join_operatorContext) IsJoin_operatorContext() {}
func NewJoin_operatorContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Join_operatorContext {
var p = new(Join_operatorContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_join_operator
return p
}
func (s *Join_operatorContext) GetParser() antlr.Parser { return s.parser }
func (s *Join_operatorContext) COMMA() antlr.TerminalNode {
return s.GetToken(ParserCOMMA, 0)
}
func (s *Join_operatorContext) JOIN_() antlr.TerminalNode {
return s.GetToken(ParserJOIN_, 0)
}
func (s *Join_operatorContext) NATURAL_() antlr.TerminalNode {
return s.GetToken(ParserNATURAL_, 0)
}
func (s *Join_operatorContext) LEFT_() antlr.TerminalNode {
return s.GetToken(ParserLEFT_, 0)
}
func (s *Join_operatorContext) INNER_() antlr.TerminalNode {
return s.GetToken(ParserINNER_, 0)
}
func (s *Join_operatorContext) CROSS_() antlr.TerminalNode {
return s.GetToken(ParserCROSS_, 0)
}
func (s *Join_operatorContext) OUTER_() antlr.TerminalNode {
return s.GetToken(ParserOUTER_, 0)
}
func (s *Join_operatorContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Join_operatorContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Join_operatorContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterJoin_operator(s)
}
}
func (s *Join_operatorContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitJoin_operator(s)
}
}
func (s *Join_operatorContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitJoin_operator(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Join_operator() (localctx IJoin_operatorContext) {
localctx = NewJoin_operatorContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 98, ParserRULE_join_operator)
var _la int
p.SetState(1511)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserCOMMA:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1498)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserCROSS_, ParserINNER_, ParserJOIN_, ParserLEFT_, ParserNATURAL_:
p.EnterOuterAlt(localctx, 2)
p.SetState(1500)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserNATURAL_ {
{
p.SetState(1499)
p.Match(ParserNATURAL_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
p.SetState(1508)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserLEFT_:
{
p.SetState(1502)
p.Match(ParserLEFT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1504)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserOUTER_ {
{
p.SetState(1503)
p.Match(ParserOUTER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
case ParserINNER_:
{
p.SetState(1506)
p.Match(ParserINNER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserCROSS_:
{
p.SetState(1507)
p.Match(ParserCROSS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserJOIN_:
default:
}
{
p.SetState(1510)
p.Match(ParserJOIN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IJoin_constraintContext is an interface to support dynamic dispatch.
type IJoin_constraintContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ON_() antlr.TerminalNode
Expr() IExprContext
USING_() antlr.TerminalNode
OPEN_PAR() antlr.TerminalNode
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
CLOSE_PAR() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsJoin_constraintContext differentiates from other interfaces.
IsJoin_constraintContext()
}
type Join_constraintContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyJoin_constraintContext() *Join_constraintContext {
var p = new(Join_constraintContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_join_constraint
return p
}
func InitEmptyJoin_constraintContext(p *Join_constraintContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_join_constraint
}
func (*Join_constraintContext) IsJoin_constraintContext() {}
func NewJoin_constraintContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Join_constraintContext {
var p = new(Join_constraintContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_join_constraint
return p
}
func (s *Join_constraintContext) GetParser() antlr.Parser { return s.parser }
func (s *Join_constraintContext) ON_() antlr.TerminalNode {
return s.GetToken(ParserON_, 0)
}
func (s *Join_constraintContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Join_constraintContext) USING_() antlr.TerminalNode {
return s.GetToken(ParserUSING_, 0)
}
func (s *Join_constraintContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Join_constraintContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Join_constraintContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Join_constraintContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Join_constraintContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Join_constraintContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Join_constraintContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Join_constraintContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Join_constraintContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterJoin_constraint(s)
}
}
func (s *Join_constraintContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitJoin_constraint(s)
}
}
func (s *Join_constraintContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitJoin_constraint(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Join_constraint() (localctx IJoin_constraintContext) {
localctx = NewJoin_constraintContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 100, ParserRULE_join_constraint)
var _la int
p.SetState(1527)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserON_:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1513)
p.Match(ParserON_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1514)
p.expr(0)
}
case ParserUSING_:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(1515)
p.Match(ParserUSING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1516)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1517)
p.Column_name()
}
p.SetState(1522)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1518)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1519)
p.Column_name()
}
p.SetState(1524)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(1525)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICompound_operatorContext is an interface to support dynamic dispatch.
type ICompound_operatorContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
UNION_() antlr.TerminalNode
ALL_() antlr.TerminalNode
INTERSECT_() antlr.TerminalNode
EXCEPT_() antlr.TerminalNode
// IsCompound_operatorContext differentiates from other interfaces.
IsCompound_operatorContext()
}
type Compound_operatorContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyCompound_operatorContext() *Compound_operatorContext {
var p = new(Compound_operatorContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_compound_operator
return p
}
func InitEmptyCompound_operatorContext(p *Compound_operatorContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_compound_operator
}
func (*Compound_operatorContext) IsCompound_operatorContext() {}
func NewCompound_operatorContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Compound_operatorContext {
var p = new(Compound_operatorContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_compound_operator
return p
}
func (s *Compound_operatorContext) GetParser() antlr.Parser { return s.parser }
func (s *Compound_operatorContext) UNION_() antlr.TerminalNode {
return s.GetToken(ParserUNION_, 0)
}
func (s *Compound_operatorContext) ALL_() antlr.TerminalNode {
return s.GetToken(ParserALL_, 0)
}
func (s *Compound_operatorContext) INTERSECT_() antlr.TerminalNode {
return s.GetToken(ParserINTERSECT_, 0)
}
func (s *Compound_operatorContext) EXCEPT_() antlr.TerminalNode {
return s.GetToken(ParserEXCEPT_, 0)
}
func (s *Compound_operatorContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Compound_operatorContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Compound_operatorContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCompound_operator(s)
}
}
func (s *Compound_operatorContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCompound_operator(s)
}
}
func (s *Compound_operatorContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCompound_operator(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Compound_operator() (localctx ICompound_operatorContext) {
localctx = NewCompound_operatorContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 102, ParserRULE_compound_operator)
var _la int
p.SetState(1535)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserUNION_:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1529)
p.Match(ParserUNION_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1531)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserALL_ {
{
p.SetState(1530)
p.Match(ParserALL_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
}
case ParserINTERSECT_:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(1533)
p.Match(ParserINTERSECT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserEXCEPT_:
p.EnterOuterAlt(localctx, 3)
{
p.SetState(1534)
p.Match(ParserEXCEPT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IUpdate_stmtContext is an interface to support dynamic dispatch.
type IUpdate_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetWhere returns the where rule contexts.
GetWhere() IExprContext
// SetWhere sets the where rule contexts.
SetWhere(IExprContext)
// Getter signatures
UPDATE_() antlr.TerminalNode
Qualified_table_name() IQualified_table_nameContext
SET_() antlr.TerminalNode
Assignment_list() IAssignment_listContext
With_clause() IWith_clauseContext
OR_() antlr.TerminalNode
FROM_() antlr.TerminalNode
WHERE_() antlr.TerminalNode
Returning_clause() IReturning_clauseContext
ROLLBACK_() antlr.TerminalNode
ABORT_() antlr.TerminalNode
REPLACE_() antlr.TerminalNode
FAIL_() antlr.TerminalNode
IGNORE_() antlr.TerminalNode
Expr() IExprContext
AllTable_or_subquery() []ITable_or_subqueryContext
Table_or_subquery(i int) ITable_or_subqueryContext
Join_clause() IJoin_clauseContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsUpdate_stmtContext differentiates from other interfaces.
IsUpdate_stmtContext()
}
type Update_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
where IExprContext
}
func NewEmptyUpdate_stmtContext() *Update_stmtContext {
var p = new(Update_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_update_stmt
return p
}
func InitEmptyUpdate_stmtContext(p *Update_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_update_stmt
}
func (*Update_stmtContext) IsUpdate_stmtContext() {}
func NewUpdate_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Update_stmtContext {
var p = new(Update_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_update_stmt
return p
}
func (s *Update_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Update_stmtContext) GetWhere() IExprContext { return s.where }
func (s *Update_stmtContext) SetWhere(v IExprContext) { s.where = v }
func (s *Update_stmtContext) UPDATE_() antlr.TerminalNode {
return s.GetToken(ParserUPDATE_, 0)
}
func (s *Update_stmtContext) Qualified_table_name() IQualified_table_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IQualified_table_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IQualified_table_nameContext)
}
func (s *Update_stmtContext) SET_() antlr.TerminalNode {
return s.GetToken(ParserSET_, 0)
}
func (s *Update_stmtContext) Assignment_list() IAssignment_listContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAssignment_listContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAssignment_listContext)
}
func (s *Update_stmtContext) With_clause() IWith_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IWith_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IWith_clauseContext)
}
func (s *Update_stmtContext) OR_() antlr.TerminalNode {
return s.GetToken(ParserOR_, 0)
}
func (s *Update_stmtContext) FROM_() antlr.TerminalNode {
return s.GetToken(ParserFROM_, 0)
}
func (s *Update_stmtContext) WHERE_() antlr.TerminalNode {
return s.GetToken(ParserWHERE_, 0)
}
func (s *Update_stmtContext) Returning_clause() IReturning_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IReturning_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IReturning_clauseContext)
}
func (s *Update_stmtContext) ROLLBACK_() antlr.TerminalNode {
return s.GetToken(ParserROLLBACK_, 0)
}
func (s *Update_stmtContext) ABORT_() antlr.TerminalNode {
return s.GetToken(ParserABORT_, 0)
}
func (s *Update_stmtContext) REPLACE_() antlr.TerminalNode {
return s.GetToken(ParserREPLACE_, 0)
}
func (s *Update_stmtContext) FAIL_() antlr.TerminalNode {
return s.GetToken(ParserFAIL_, 0)
}
func (s *Update_stmtContext) IGNORE_() antlr.TerminalNode {
return s.GetToken(ParserIGNORE_, 0)
}
func (s *Update_stmtContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Update_stmtContext) AllTable_or_subquery() []ITable_or_subqueryContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ITable_or_subqueryContext); ok {
len++
}
}
tst := make([]ITable_or_subqueryContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ITable_or_subqueryContext); ok {
tst[i] = t.(ITable_or_subqueryContext)
i++
}
}
return tst
}
func (s *Update_stmtContext) Table_or_subquery(i int) ITable_or_subqueryContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_or_subqueryContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ITable_or_subqueryContext)
}
func (s *Update_stmtContext) Join_clause() IJoin_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IJoin_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IJoin_clauseContext)
}
func (s *Update_stmtContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Update_stmtContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Update_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Update_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Update_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterUpdate_stmt(s)
}
}
func (s *Update_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitUpdate_stmt(s)
}
}
func (s *Update_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitUpdate_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Update_stmt() (localctx IUpdate_stmtContext) {
localctx = NewUpdate_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 104, ParserRULE_update_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(1538)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWITH_ {
{
p.SetState(1537)
p.With_clause()
}
}
{
p.SetState(1540)
p.Match(ParserUPDATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1543)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 221, p.GetParserRuleContext()) == 1 {
{
p.SetState(1541)
p.Match(ParserOR_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1542)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserABORT_ || ((int64((_la-72)) & ^0x3f) == 0 && ((int64(1)<<(_la-72))&19140298416325121) != 0)) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1545)
p.Qualified_table_name()
}
{
p.SetState(1546)
p.Match(ParserSET_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1547)
p.Assignment_list()
}
p.SetState(1560)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserFROM_ {
{
p.SetState(1548)
p.Match(ParserFROM_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1558)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 223, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1549)
p.Table_or_subquery()
}
p.SetState(1554)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1550)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1551)
p.Table_or_subquery()
}
p.SetState(1556)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
case 2:
{
p.SetState(1557)
p.Join_clause()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
}
p.SetState(1564)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWHERE_ {
{
p.SetState(1562)
p.Match(ParserWHERE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1563)
var _x = p.expr(0)
localctx.(*Update_stmtContext).where = _x
}
}
p.SetState(1567)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserRETURNING_ {
{
p.SetState(1566)
p.Returning_clause()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IAssignment_listContext is an interface to support dynamic dispatch.
type IAssignment_listContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
AllAssignment() []IAssignmentContext
Assignment(i int) IAssignmentContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsAssignment_listContext differentiates from other interfaces.
IsAssignment_listContext()
}
type Assignment_listContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyAssignment_listContext() *Assignment_listContext {
var p = new(Assignment_listContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_assignment_list
return p
}
func InitEmptyAssignment_listContext(p *Assignment_listContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_assignment_list
}
func (*Assignment_listContext) IsAssignment_listContext() {}
func NewAssignment_listContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Assignment_listContext {
var p = new(Assignment_listContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_assignment_list
return p
}
func (s *Assignment_listContext) GetParser() antlr.Parser { return s.parser }
func (s *Assignment_listContext) AllAssignment() []IAssignmentContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IAssignmentContext); ok {
len++
}
}
tst := make([]IAssignmentContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IAssignmentContext); ok {
tst[i] = t.(IAssignmentContext)
i++
}
}
return tst
}
func (s *Assignment_listContext) Assignment(i int) IAssignmentContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAssignmentContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IAssignmentContext)
}
func (s *Assignment_listContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Assignment_listContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Assignment_listContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Assignment_listContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Assignment_listContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterAssignment_list(s)
}
}
func (s *Assignment_listContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitAssignment_list(s)
}
}
func (s *Assignment_listContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitAssignment_list(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Assignment_list() (localctx IAssignment_listContext) {
localctx = NewAssignment_listContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 106, ParserRULE_assignment_list)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1569)
p.Assignment()
}
p.SetState(1574)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1570)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1571)
p.Assignment()
}
p.SetState(1576)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IAssignmentContext is an interface to support dynamic dispatch.
type IAssignmentContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ASSIGN() antlr.TerminalNode
Expr() IExprContext
Column_name() IColumn_nameContext
Column_name_list() IColumn_name_listContext
// IsAssignmentContext differentiates from other interfaces.
IsAssignmentContext()
}
type AssignmentContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyAssignmentContext() *AssignmentContext {
var p = new(AssignmentContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_assignment
return p
}
func InitEmptyAssignmentContext(p *AssignmentContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_assignment
}
func (*AssignmentContext) IsAssignmentContext() {}
func NewAssignmentContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *AssignmentContext {
var p = new(AssignmentContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_assignment
return p
}
func (s *AssignmentContext) GetParser() antlr.Parser { return s.parser }
func (s *AssignmentContext) ASSIGN() antlr.TerminalNode {
return s.GetToken(ParserASSIGN, 0)
}
func (s *AssignmentContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *AssignmentContext) Column_name() IColumn_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *AssignmentContext) Column_name_list() IColumn_name_listContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_name_listContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IColumn_name_listContext)
}
func (s *AssignmentContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *AssignmentContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *AssignmentContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterAssignment(s)
}
}
func (s *AssignmentContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitAssignment(s)
}
}
func (s *AssignmentContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitAssignment(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Assignment() (localctx IAssignmentContext) {
localctx = NewAssignmentContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 108, ParserRULE_assignment)
p.EnterOuterAlt(localctx, 1)
p.SetState(1579)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 228, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1577)
p.Column_name()
}
case 2:
{
p.SetState(1578)
p.Column_name_list()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
{
p.SetState(1581)
p.Match(ParserASSIGN)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1582)
p.expr(0)
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IColumn_name_listContext is an interface to support dynamic dispatch.
type IColumn_name_listContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
OPEN_PAR() antlr.TerminalNode
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
CLOSE_PAR() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsColumn_name_listContext differentiates from other interfaces.
IsColumn_name_listContext()
}
type Column_name_listContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyColumn_name_listContext() *Column_name_listContext {
var p = new(Column_name_listContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_column_name_list
return p
}
func InitEmptyColumn_name_listContext(p *Column_name_listContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_column_name_list
}
func (*Column_name_listContext) IsColumn_name_listContext() {}
func NewColumn_name_listContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Column_name_listContext {
var p = new(Column_name_listContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_column_name_list
return p
}
func (s *Column_name_listContext) GetParser() antlr.Parser { return s.parser }
func (s *Column_name_listContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Column_name_listContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Column_name_listContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Column_name_listContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Column_name_listContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Column_name_listContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Column_name_listContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Column_name_listContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Column_name_listContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterColumn_name_list(s)
}
}
func (s *Column_name_listContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitColumn_name_list(s)
}
}
func (s *Column_name_listContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitColumn_name_list(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Column_name_list() (localctx IColumn_name_listContext) {
localctx = NewColumn_name_listContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 110, ParserRULE_column_name_list)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1584)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1585)
p.Column_name()
}
p.SetState(1590)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1586)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1587)
p.Column_name()
}
p.SetState(1592)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(1593)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IUpdate_stmt_limitedContext is an interface to support dynamic dispatch.
type IUpdate_stmt_limitedContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
UPDATE_() antlr.TerminalNode
Qualified_table_name() IQualified_table_nameContext
SET_() antlr.TerminalNode
AllASSIGN() []antlr.TerminalNode
ASSIGN(i int) antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
AllColumn_name() []IColumn_nameContext
Column_name(i int) IColumn_nameContext
AllColumn_name_list() []IColumn_name_listContext
Column_name_list(i int) IColumn_name_listContext
With_clause() IWith_clauseContext
OR_() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
WHERE_() antlr.TerminalNode
Returning_clause() IReturning_clauseContext
Limit_stmt() ILimit_stmtContext
ROLLBACK_() antlr.TerminalNode
ABORT_() antlr.TerminalNode
REPLACE_() antlr.TerminalNode
FAIL_() antlr.TerminalNode
IGNORE_() antlr.TerminalNode
Order_by_stmt() IOrder_by_stmtContext
// IsUpdate_stmt_limitedContext differentiates from other interfaces.
IsUpdate_stmt_limitedContext()
}
type Update_stmt_limitedContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyUpdate_stmt_limitedContext() *Update_stmt_limitedContext {
var p = new(Update_stmt_limitedContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_update_stmt_limited
return p
}
func InitEmptyUpdate_stmt_limitedContext(p *Update_stmt_limitedContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_update_stmt_limited
}
func (*Update_stmt_limitedContext) IsUpdate_stmt_limitedContext() {}
func NewUpdate_stmt_limitedContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Update_stmt_limitedContext {
var p = new(Update_stmt_limitedContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_update_stmt_limited
return p
}
func (s *Update_stmt_limitedContext) GetParser() antlr.Parser { return s.parser }
func (s *Update_stmt_limitedContext) UPDATE_() antlr.TerminalNode {
return s.GetToken(ParserUPDATE_, 0)
}
func (s *Update_stmt_limitedContext) Qualified_table_name() IQualified_table_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IQualified_table_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IQualified_table_nameContext)
}
func (s *Update_stmt_limitedContext) SET_() antlr.TerminalNode {
return s.GetToken(ParserSET_, 0)
}
func (s *Update_stmt_limitedContext) AllASSIGN() []antlr.TerminalNode {
return s.GetTokens(ParserASSIGN)
}
func (s *Update_stmt_limitedContext) ASSIGN(i int) antlr.TerminalNode {
return s.GetToken(ParserASSIGN, i)
}
func (s *Update_stmt_limitedContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Update_stmt_limitedContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Update_stmt_limitedContext) AllColumn_name() []IColumn_nameContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_nameContext); ok {
len++
}
}
tst := make([]IColumn_nameContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_nameContext); ok {
tst[i] = t.(IColumn_nameContext)
i++
}
}
return tst
}
func (s *Update_stmt_limitedContext) Column_name(i int) IColumn_nameContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_nameContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_nameContext)
}
func (s *Update_stmt_limitedContext) AllColumn_name_list() []IColumn_name_listContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IColumn_name_listContext); ok {
len++
}
}
tst := make([]IColumn_name_listContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IColumn_name_listContext); ok {
tst[i] = t.(IColumn_name_listContext)
i++
}
}
return tst
}
func (s *Update_stmt_limitedContext) Column_name_list(i int) IColumn_name_listContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_name_listContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IColumn_name_listContext)
}
func (s *Update_stmt_limitedContext) With_clause() IWith_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IWith_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IWith_clauseContext)
}
func (s *Update_stmt_limitedContext) OR_() antlr.TerminalNode {
return s.GetToken(ParserOR_, 0)
}
func (s *Update_stmt_limitedContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Update_stmt_limitedContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Update_stmt_limitedContext) WHERE_() antlr.TerminalNode {
return s.GetToken(ParserWHERE_, 0)
}
func (s *Update_stmt_limitedContext) Returning_clause() IReturning_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IReturning_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IReturning_clauseContext)
}
func (s *Update_stmt_limitedContext) Limit_stmt() ILimit_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ILimit_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ILimit_stmtContext)
}
func (s *Update_stmt_limitedContext) ROLLBACK_() antlr.TerminalNode {
return s.GetToken(ParserROLLBACK_, 0)
}
func (s *Update_stmt_limitedContext) ABORT_() antlr.TerminalNode {
return s.GetToken(ParserABORT_, 0)
}
func (s *Update_stmt_limitedContext) REPLACE_() antlr.TerminalNode {
return s.GetToken(ParserREPLACE_, 0)
}
func (s *Update_stmt_limitedContext) FAIL_() antlr.TerminalNode {
return s.GetToken(ParserFAIL_, 0)
}
func (s *Update_stmt_limitedContext) IGNORE_() antlr.TerminalNode {
return s.GetToken(ParserIGNORE_, 0)
}
func (s *Update_stmt_limitedContext) Order_by_stmt() IOrder_by_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOrder_by_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IOrder_by_stmtContext)
}
func (s *Update_stmt_limitedContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Update_stmt_limitedContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Update_stmt_limitedContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterUpdate_stmt_limited(s)
}
}
func (s *Update_stmt_limitedContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitUpdate_stmt_limited(s)
}
}
func (s *Update_stmt_limitedContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitUpdate_stmt_limited(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Update_stmt_limited() (localctx IUpdate_stmt_limitedContext) {
localctx = NewUpdate_stmt_limitedContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 112, ParserRULE_update_stmt_limited)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(1596)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWITH_ {
{
p.SetState(1595)
p.With_clause()
}
}
{
p.SetState(1598)
p.Match(ParserUPDATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1601)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 231, p.GetParserRuleContext()) == 1 {
{
p.SetState(1599)
p.Match(ParserOR_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1600)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserABORT_ || ((int64((_la-72)) & ^0x3f) == 0 && ((int64(1)<<(_la-72))&19140298416325121) != 0)) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1603)
p.Qualified_table_name()
}
{
p.SetState(1604)
p.Match(ParserSET_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1607)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 232, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1605)
p.Column_name()
}
case 2:
{
p.SetState(1606)
p.Column_name_list()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
{
p.SetState(1609)
p.Match(ParserASSIGN)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1610)
p.expr(0)
}
p.SetState(1621)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1611)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1614)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 233, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1612)
p.Column_name()
}
case 2:
{
p.SetState(1613)
p.Column_name_list()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
{
p.SetState(1616)
p.Match(ParserASSIGN)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1617)
p.expr(0)
}
p.SetState(1623)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
p.SetState(1626)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserWHERE_ {
{
p.SetState(1624)
p.Match(ParserWHERE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1625)
p.expr(0)
}
}
p.SetState(1629)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserRETURNING_ {
{
p.SetState(1628)
p.Returning_clause()
}
}
p.SetState(1635)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserLIMIT_ || _la == ParserORDER_ {
p.SetState(1632)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserORDER_ {
{
p.SetState(1631)
p.Order_by_stmt()
}
}
{
p.SetState(1634)
p.Limit_stmt()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IQualified_table_nameContext is an interface to support dynamic dispatch.
type IQualified_table_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Table_name() ITable_nameContext
Schema_name() ISchema_nameContext
DOT() antlr.TerminalNode
AS_() antlr.TerminalNode
Alias() IAliasContext
INDEXED_() antlr.TerminalNode
BY_() antlr.TerminalNode
Index_name() IIndex_nameContext
NOT_() antlr.TerminalNode
// IsQualified_table_nameContext differentiates from other interfaces.
IsQualified_table_nameContext()
}
type Qualified_table_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyQualified_table_nameContext() *Qualified_table_nameContext {
var p = new(Qualified_table_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_qualified_table_name
return p
}
func InitEmptyQualified_table_nameContext(p *Qualified_table_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_qualified_table_name
}
func (*Qualified_table_nameContext) IsQualified_table_nameContext() {}
func NewQualified_table_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Qualified_table_nameContext {
var p = new(Qualified_table_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_qualified_table_name
return p
}
func (s *Qualified_table_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Qualified_table_nameContext) Table_name() ITable_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ITable_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ITable_nameContext)
}
func (s *Qualified_table_nameContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Qualified_table_nameContext) DOT() antlr.TerminalNode {
return s.GetToken(ParserDOT, 0)
}
func (s *Qualified_table_nameContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *Qualified_table_nameContext) Alias() IAliasContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAliasContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAliasContext)
}
func (s *Qualified_table_nameContext) INDEXED_() antlr.TerminalNode {
return s.GetToken(ParserINDEXED_, 0)
}
func (s *Qualified_table_nameContext) BY_() antlr.TerminalNode {
return s.GetToken(ParserBY_, 0)
}
func (s *Qualified_table_nameContext) Index_name() IIndex_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IIndex_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IIndex_nameContext)
}
func (s *Qualified_table_nameContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *Qualified_table_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Qualified_table_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Qualified_table_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterQualified_table_name(s)
}
}
func (s *Qualified_table_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitQualified_table_name(s)
}
}
func (s *Qualified_table_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitQualified_table_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Qualified_table_name() (localctx IQualified_table_nameContext) {
localctx = NewQualified_table_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 114, ParserRULE_qualified_table_name)
var _la int
p.EnterOuterAlt(localctx, 1)
p.SetState(1640)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 239, p.GetParserRuleContext()) == 1 {
{
p.SetState(1637)
p.Schema_name()
}
{
p.SetState(1638)
p.Match(ParserDOT)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1642)
p.Table_name()
}
p.SetState(1645)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserAS_ {
{
p.SetState(1643)
p.Match(ParserAS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1644)
p.Alias()
}
}
p.SetState(1652)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserINDEXED_:
{
p.SetState(1647)
p.Match(ParserINDEXED_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1648)
p.Match(ParserBY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1649)
p.Index_name()
}
case ParserNOT_:
{
p.SetState(1650)
p.Match(ParserNOT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1651)
p.Match(ParserINDEXED_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserEOF, ParserSCOL, ParserALTER_, ParserANALYZE_, ParserATTACH_, ParserBEGIN_, ParserCOMMIT_, ParserCREATE_, ParserDELETE_, ParserDETACH_, ParserDROP_, ParserEND_, ParserEXPLAIN_, ParserINSERT_, ParserLIMIT_, ParserORDER_, ParserPRAGMA_, ParserREINDEX_, ParserRELEASE_, ParserREPLACE_, ParserRETURNING_, ParserROLLBACK_, ParserSAVEPOINT_, ParserSELECT_, ParserSET_, ParserUPDATE_, ParserVACUUM_, ParserVALUES_, ParserWHERE_, ParserWITH_:
default:
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IVacuum_stmtContext is an interface to support dynamic dispatch.
type IVacuum_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
VACUUM_() antlr.TerminalNode
Schema_name() ISchema_nameContext
INTO_() antlr.TerminalNode
Filename() IFilenameContext
// IsVacuum_stmtContext differentiates from other interfaces.
IsVacuum_stmtContext()
}
type Vacuum_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyVacuum_stmtContext() *Vacuum_stmtContext {
var p = new(Vacuum_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_vacuum_stmt
return p
}
func InitEmptyVacuum_stmtContext(p *Vacuum_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_vacuum_stmt
}
func (*Vacuum_stmtContext) IsVacuum_stmtContext() {}
func NewVacuum_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Vacuum_stmtContext {
var p = new(Vacuum_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_vacuum_stmt
return p
}
func (s *Vacuum_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Vacuum_stmtContext) VACUUM_() antlr.TerminalNode {
return s.GetToken(ParserVACUUM_, 0)
}
func (s *Vacuum_stmtContext) Schema_name() ISchema_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISchema_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISchema_nameContext)
}
func (s *Vacuum_stmtContext) INTO_() antlr.TerminalNode {
return s.GetToken(ParserINTO_, 0)
}
func (s *Vacuum_stmtContext) Filename() IFilenameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFilenameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFilenameContext)
}
func (s *Vacuum_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Vacuum_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Vacuum_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterVacuum_stmt(s)
}
}
func (s *Vacuum_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitVacuum_stmt(s)
}
}
func (s *Vacuum_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitVacuum_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Vacuum_stmt() (localctx IVacuum_stmtContext) {
localctx = NewVacuum_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 116, ParserRULE_vacuum_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1654)
p.Match(ParserVACUUM_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1656)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 242, p.GetParserRuleContext()) == 1 {
{
p.SetState(1655)
p.Schema_name()
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(1660)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserINTO_ {
{
p.SetState(1658)
p.Match(ParserINTO_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1659)
p.Filename()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IFilter_clauseContext is an interface to support dynamic dispatch.
type IFilter_clauseContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
FILTER_() antlr.TerminalNode
OPEN_PAR() antlr.TerminalNode
WHERE_() antlr.TerminalNode
Expr() IExprContext
CLOSE_PAR() antlr.TerminalNode
// IsFilter_clauseContext differentiates from other interfaces.
IsFilter_clauseContext()
}
type Filter_clauseContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyFilter_clauseContext() *Filter_clauseContext {
var p = new(Filter_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_filter_clause
return p
}
func InitEmptyFilter_clauseContext(p *Filter_clauseContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_filter_clause
}
func (*Filter_clauseContext) IsFilter_clauseContext() {}
func NewFilter_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Filter_clauseContext {
var p = new(Filter_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_filter_clause
return p
}
func (s *Filter_clauseContext) GetParser() antlr.Parser { return s.parser }
func (s *Filter_clauseContext) FILTER_() antlr.TerminalNode {
return s.GetToken(ParserFILTER_, 0)
}
func (s *Filter_clauseContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Filter_clauseContext) WHERE_() antlr.TerminalNode {
return s.GetToken(ParserWHERE_, 0)
}
func (s *Filter_clauseContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Filter_clauseContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Filter_clauseContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Filter_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Filter_clauseContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterFilter_clause(s)
}
}
func (s *Filter_clauseContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitFilter_clause(s)
}
}
func (s *Filter_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitFilter_clause(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Filter_clause() (localctx IFilter_clauseContext) {
localctx = NewFilter_clauseContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 118, ParserRULE_filter_clause)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1662)
p.Match(ParserFILTER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1663)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1664)
p.Match(ParserWHERE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1665)
p.expr(0)
}
{
p.SetState(1666)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IWindow_defnContext is an interface to support dynamic dispatch.
type IWindow_defnContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
OPEN_PAR() antlr.TerminalNode
CLOSE_PAR() antlr.TerminalNode
ORDER_() antlr.TerminalNode
AllBY_() []antlr.TerminalNode
BY_(i int) antlr.TerminalNode
AllOrdering_term() []IOrdering_termContext
Ordering_term(i int) IOrdering_termContext
Base_window_name() IBase_window_nameContext
PARTITION_() antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
Frame_spec() IFrame_specContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsWindow_defnContext differentiates from other interfaces.
IsWindow_defnContext()
}
type Window_defnContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyWindow_defnContext() *Window_defnContext {
var p = new(Window_defnContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_window_defn
return p
}
func InitEmptyWindow_defnContext(p *Window_defnContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_window_defn
}
func (*Window_defnContext) IsWindow_defnContext() {}
func NewWindow_defnContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Window_defnContext {
var p = new(Window_defnContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_window_defn
return p
}
func (s *Window_defnContext) GetParser() antlr.Parser { return s.parser }
func (s *Window_defnContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Window_defnContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Window_defnContext) ORDER_() antlr.TerminalNode {
return s.GetToken(ParserORDER_, 0)
}
func (s *Window_defnContext) AllBY_() []antlr.TerminalNode {
return s.GetTokens(ParserBY_)
}
func (s *Window_defnContext) BY_(i int) antlr.TerminalNode {
return s.GetToken(ParserBY_, i)
}
func (s *Window_defnContext) AllOrdering_term() []IOrdering_termContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IOrdering_termContext); ok {
len++
}
}
tst := make([]IOrdering_termContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IOrdering_termContext); ok {
tst[i] = t.(IOrdering_termContext)
i++
}
}
return tst
}
func (s *Window_defnContext) Ordering_term(i int) IOrdering_termContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOrdering_termContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IOrdering_termContext)
}
func (s *Window_defnContext) Base_window_name() IBase_window_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IBase_window_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IBase_window_nameContext)
}
func (s *Window_defnContext) PARTITION_() antlr.TerminalNode {
return s.GetToken(ParserPARTITION_, 0)
}
func (s *Window_defnContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Window_defnContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Window_defnContext) Frame_spec() IFrame_specContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFrame_specContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFrame_specContext)
}
func (s *Window_defnContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Window_defnContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Window_defnContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Window_defnContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Window_defnContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterWindow_defn(s)
}
}
func (s *Window_defnContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitWindow_defn(s)
}
}
func (s *Window_defnContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitWindow_defn(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Window_defn() (localctx IWindow_defnContext) {
localctx = NewWindow_defnContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 120, ParserRULE_window_defn)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1668)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1670)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 244, p.GetParserRuleContext()) == 1 {
{
p.SetState(1669)
p.Base_window_name()
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(1682)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserPARTITION_ {
{
p.SetState(1672)
p.Match(ParserPARTITION_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1673)
p.Match(ParserBY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1674)
p.expr(0)
}
p.SetState(1679)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1675)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1676)
p.expr(0)
}
p.SetState(1681)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
}
{
p.SetState(1684)
p.Match(ParserORDER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1685)
p.Match(ParserBY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1686)
p.Ordering_term()
}
p.SetState(1691)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1687)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1688)
p.Ordering_term()
}
p.SetState(1693)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
p.SetState(1695)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if (int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&2251799880794113) != 0 {
{
p.SetState(1694)
p.Frame_spec()
}
}
{
p.SetState(1697)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IOver_clauseContext is an interface to support dynamic dispatch.
type IOver_clauseContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
OVER_() antlr.TerminalNode
Window_name() IWindow_nameContext
OPEN_PAR() antlr.TerminalNode
CLOSE_PAR() antlr.TerminalNode
Base_window_name() IBase_window_nameContext
PARTITION_() antlr.TerminalNode
AllBY_() []antlr.TerminalNode
BY_(i int) antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
ORDER_() antlr.TerminalNode
AllOrdering_term() []IOrdering_termContext
Ordering_term(i int) IOrdering_termContext
Frame_spec() IFrame_specContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsOver_clauseContext differentiates from other interfaces.
IsOver_clauseContext()
}
type Over_clauseContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyOver_clauseContext() *Over_clauseContext {
var p = new(Over_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_over_clause
return p
}
func InitEmptyOver_clauseContext(p *Over_clauseContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_over_clause
}
func (*Over_clauseContext) IsOver_clauseContext() {}
func NewOver_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Over_clauseContext {
var p = new(Over_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_over_clause
return p
}
func (s *Over_clauseContext) GetParser() antlr.Parser { return s.parser }
func (s *Over_clauseContext) OVER_() antlr.TerminalNode {
return s.GetToken(ParserOVER_, 0)
}
func (s *Over_clauseContext) Window_name() IWindow_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IWindow_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IWindow_nameContext)
}
func (s *Over_clauseContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Over_clauseContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Over_clauseContext) Base_window_name() IBase_window_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IBase_window_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IBase_window_nameContext)
}
func (s *Over_clauseContext) PARTITION_() antlr.TerminalNode {
return s.GetToken(ParserPARTITION_, 0)
}
func (s *Over_clauseContext) AllBY_() []antlr.TerminalNode {
return s.GetTokens(ParserBY_)
}
func (s *Over_clauseContext) BY_(i int) antlr.TerminalNode {
return s.GetToken(ParserBY_, i)
}
func (s *Over_clauseContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Over_clauseContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Over_clauseContext) ORDER_() antlr.TerminalNode {
return s.GetToken(ParserORDER_, 0)
}
func (s *Over_clauseContext) AllOrdering_term() []IOrdering_termContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IOrdering_termContext); ok {
len++
}
}
tst := make([]IOrdering_termContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IOrdering_termContext); ok {
tst[i] = t.(IOrdering_termContext)
i++
}
}
return tst
}
func (s *Over_clauseContext) Ordering_term(i int) IOrdering_termContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOrdering_termContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IOrdering_termContext)
}
func (s *Over_clauseContext) Frame_spec() IFrame_specContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFrame_specContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFrame_specContext)
}
func (s *Over_clauseContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Over_clauseContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Over_clauseContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Over_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Over_clauseContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterOver_clause(s)
}
}
func (s *Over_clauseContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitOver_clause(s)
}
}
func (s *Over_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitOver_clause(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Over_clause() (localctx IOver_clauseContext) {
localctx = NewOver_clauseContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 122, ParserRULE_over_clause)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1699)
p.Match(ParserOVER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1733)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 255, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1700)
p.Window_name()
}
case 2:
{
p.SetState(1701)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1703)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 249, p.GetParserRuleContext()) == 1 {
{
p.SetState(1702)
p.Base_window_name()
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(1715)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserPARTITION_ {
{
p.SetState(1705)
p.Match(ParserPARTITION_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1706)
p.Match(ParserBY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1707)
p.expr(0)
}
p.SetState(1712)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1708)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1709)
p.expr(0)
}
p.SetState(1714)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
}
p.SetState(1727)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserORDER_ {
{
p.SetState(1717)
p.Match(ParserORDER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1718)
p.Match(ParserBY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1719)
p.Ordering_term()
}
p.SetState(1724)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1720)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1721)
p.Ordering_term()
}
p.SetState(1726)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
}
p.SetState(1730)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if (int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&2251799880794113) != 0 {
{
p.SetState(1729)
p.Frame_spec()
}
}
{
p.SetState(1732)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IFrame_specContext is an interface to support dynamic dispatch.
type IFrame_specContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Frame_clause() IFrame_clauseContext
EXCLUDE_() antlr.TerminalNode
CURRENT_() antlr.TerminalNode
ROW_() antlr.TerminalNode
GROUP_() antlr.TerminalNode
TIES_() antlr.TerminalNode
NO_() antlr.TerminalNode
OTHERS_() antlr.TerminalNode
// IsFrame_specContext differentiates from other interfaces.
IsFrame_specContext()
}
type Frame_specContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyFrame_specContext() *Frame_specContext {
var p = new(Frame_specContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_frame_spec
return p
}
func InitEmptyFrame_specContext(p *Frame_specContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_frame_spec
}
func (*Frame_specContext) IsFrame_specContext() {}
func NewFrame_specContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Frame_specContext {
var p = new(Frame_specContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_frame_spec
return p
}
func (s *Frame_specContext) GetParser() antlr.Parser { return s.parser }
func (s *Frame_specContext) Frame_clause() IFrame_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFrame_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFrame_clauseContext)
}
func (s *Frame_specContext) EXCLUDE_() antlr.TerminalNode {
return s.GetToken(ParserEXCLUDE_, 0)
}
func (s *Frame_specContext) CURRENT_() antlr.TerminalNode {
return s.GetToken(ParserCURRENT_, 0)
}
func (s *Frame_specContext) ROW_() antlr.TerminalNode {
return s.GetToken(ParserROW_, 0)
}
func (s *Frame_specContext) GROUP_() antlr.TerminalNode {
return s.GetToken(ParserGROUP_, 0)
}
func (s *Frame_specContext) TIES_() antlr.TerminalNode {
return s.GetToken(ParserTIES_, 0)
}
func (s *Frame_specContext) NO_() antlr.TerminalNode {
return s.GetToken(ParserNO_, 0)
}
func (s *Frame_specContext) OTHERS_() antlr.TerminalNode {
return s.GetToken(ParserOTHERS_, 0)
}
func (s *Frame_specContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Frame_specContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Frame_specContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterFrame_spec(s)
}
}
func (s *Frame_specContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitFrame_spec(s)
}
}
func (s *Frame_specContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitFrame_spec(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Frame_spec() (localctx IFrame_specContext) {
localctx = NewFrame_specContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 124, ParserRULE_frame_spec)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1735)
p.Frame_clause()
}
p.SetState(1743)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserEXCLUDE_:
{
p.SetState(1736)
p.Match(ParserEXCLUDE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1737)
p.Match(ParserNO_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1738)
p.Match(ParserOTHERS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserCURRENT_:
{
p.SetState(1739)
p.Match(ParserCURRENT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1740)
p.Match(ParserROW_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserGROUP_:
{
p.SetState(1741)
p.Match(ParserGROUP_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserTIES_:
{
p.SetState(1742)
p.Match(ParserTIES_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserCLOSE_PAR:
default:
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IFrame_clauseContext is an interface to support dynamic dispatch.
type IFrame_clauseContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
RANGE_() antlr.TerminalNode
ROWS_() antlr.TerminalNode
GROUPS_() antlr.TerminalNode
Frame_single() IFrame_singleContext
BETWEEN_() antlr.TerminalNode
Frame_left() IFrame_leftContext
AND_() antlr.TerminalNode
Frame_right() IFrame_rightContext
// IsFrame_clauseContext differentiates from other interfaces.
IsFrame_clauseContext()
}
type Frame_clauseContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyFrame_clauseContext() *Frame_clauseContext {
var p = new(Frame_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_frame_clause
return p
}
func InitEmptyFrame_clauseContext(p *Frame_clauseContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_frame_clause
}
func (*Frame_clauseContext) IsFrame_clauseContext() {}
func NewFrame_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Frame_clauseContext {
var p = new(Frame_clauseContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_frame_clause
return p
}
func (s *Frame_clauseContext) GetParser() antlr.Parser { return s.parser }
func (s *Frame_clauseContext) RANGE_() antlr.TerminalNode {
return s.GetToken(ParserRANGE_, 0)
}
func (s *Frame_clauseContext) ROWS_() antlr.TerminalNode {
return s.GetToken(ParserROWS_, 0)
}
func (s *Frame_clauseContext) GROUPS_() antlr.TerminalNode {
return s.GetToken(ParserGROUPS_, 0)
}
func (s *Frame_clauseContext) Frame_single() IFrame_singleContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFrame_singleContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFrame_singleContext)
}
func (s *Frame_clauseContext) BETWEEN_() antlr.TerminalNode {
return s.GetToken(ParserBETWEEN_, 0)
}
func (s *Frame_clauseContext) Frame_left() IFrame_leftContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFrame_leftContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFrame_leftContext)
}
func (s *Frame_clauseContext) AND_() antlr.TerminalNode {
return s.GetToken(ParserAND_, 0)
}
func (s *Frame_clauseContext) Frame_right() IFrame_rightContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFrame_rightContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFrame_rightContext)
}
func (s *Frame_clauseContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Frame_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Frame_clauseContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterFrame_clause(s)
}
}
func (s *Frame_clauseContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitFrame_clause(s)
}
}
func (s *Frame_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitFrame_clause(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Frame_clause() (localctx IFrame_clauseContext) {
localctx = NewFrame_clauseContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 126, ParserRULE_frame_clause)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1745)
_la = p.GetTokenStream().LA(1)
if !((int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&2251799880794113) != 0) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
p.SetState(1752)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 257, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1746)
p.Frame_single()
}
case 2:
{
p.SetState(1747)
p.Match(ParserBETWEEN_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1748)
p.Frame_left()
}
{
p.SetState(1749)
p.Match(ParserAND_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1750)
p.Frame_right()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ISimple_function_invocationContext is an interface to support dynamic dispatch.
type ISimple_function_invocationContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Simple_func() ISimple_funcContext
OPEN_PAR() antlr.TerminalNode
CLOSE_PAR() antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
STAR() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsSimple_function_invocationContext differentiates from other interfaces.
IsSimple_function_invocationContext()
}
type Simple_function_invocationContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptySimple_function_invocationContext() *Simple_function_invocationContext {
var p = new(Simple_function_invocationContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_simple_function_invocation
return p
}
func InitEmptySimple_function_invocationContext(p *Simple_function_invocationContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_simple_function_invocation
}
func (*Simple_function_invocationContext) IsSimple_function_invocationContext() {}
func NewSimple_function_invocationContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Simple_function_invocationContext {
var p = new(Simple_function_invocationContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_simple_function_invocation
return p
}
func (s *Simple_function_invocationContext) GetParser() antlr.Parser { return s.parser }
func (s *Simple_function_invocationContext) Simple_func() ISimple_funcContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISimple_funcContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISimple_funcContext)
}
func (s *Simple_function_invocationContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Simple_function_invocationContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Simple_function_invocationContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Simple_function_invocationContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Simple_function_invocationContext) STAR() antlr.TerminalNode {
return s.GetToken(ParserSTAR, 0)
}
func (s *Simple_function_invocationContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Simple_function_invocationContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Simple_function_invocationContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Simple_function_invocationContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Simple_function_invocationContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterSimple_function_invocation(s)
}
}
func (s *Simple_function_invocationContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitSimple_function_invocation(s)
}
}
func (s *Simple_function_invocationContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitSimple_function_invocation(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Simple_function_invocation() (localctx ISimple_function_invocationContext) {
localctx = NewSimple_function_invocationContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 128, ParserRULE_simple_function_invocation)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1754)
p.Simple_func()
}
{
p.SetState(1755)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1765)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserOPEN_PAR, ParserPLUS, ParserMINUS, ParserTILDE, ParserABORT_, ParserACTION_, ParserADD_, ParserAFTER_, ParserALL_, ParserALTER_, ParserANALYZE_, ParserAND_, ParserAS_, ParserASC_, ParserATTACH_, ParserAUTOINCREMENT_, ParserBEFORE_, ParserBEGIN_, ParserBETWEEN_, ParserBY_, ParserCASCADE_, ParserCASE_, ParserCAST_, ParserCHECK_, ParserCOLLATE_, ParserCOLUMN_, ParserCOMMIT_, ParserCONFLICT_, ParserCONSTRAINT_, ParserCREATE_, ParserCROSS_, ParserCURRENT_DATE_, ParserCURRENT_TIME_, ParserCURRENT_TIMESTAMP_, ParserDATABASE_, ParserDEFAULT_, ParserDEFERRABLE_, ParserDEFERRED_, ParserDELETE_, ParserDESC_, ParserDETACH_, ParserDISTINCT_, ParserDROP_, ParserEACH_, ParserELSE_, ParserEND_, ParserESCAPE_, ParserEXCEPT_, ParserEXCLUSIVE_, ParserEXISTS_, ParserEXPLAIN_, ParserFAIL_, ParserFOR_, ParserFOREIGN_, ParserFROM_, ParserFULL_, ParserGLOB_, ParserGROUP_, ParserHAVING_, ParserIF_, ParserIGNORE_, ParserIMMEDIATE_, ParserIN_, ParserINDEX_, ParserINDEXED_, ParserINITIALLY_, ParserINNER_, ParserINSERT_, ParserINSTEAD_, ParserINTERSECT_, ParserINTO_, ParserIS_, ParserISNULL_, ParserJOIN_, ParserKEY_, ParserLEFT_, ParserLIKE_, ParserLIMIT_, ParserMATCH_, ParserNATURAL_, ParserNO_, ParserNOT_, ParserNOTNULL_, ParserNULL_, ParserOF_, ParserOFFSET_, ParserON_, ParserOR_, ParserORDER_, ParserOUTER_, ParserPLAN_, ParserPRAGMA_, ParserPRIMARY_, ParserQUERY_, ParserRAISE_, ParserRECURSIVE_, ParserREFERENCES_, ParserREGEXP_, ParserREINDEX_, ParserRELEASE_, ParserRENAME_, ParserREPLACE_, ParserRESTRICT_, ParserRIGHT_, ParserROLLBACK_, ParserROW_, ParserROWS_, ParserSAVEPOINT_, ParserSELECT_, ParserSET_, ParserTABLE_, ParserTEMP_, ParserTEMPORARY_, ParserTHEN_, ParserTO_, ParserTRANSACTION_, ParserTRIGGER_, ParserUNION_, ParserUNIQUE_, ParserUPDATE_, ParserUSING_, ParserVACUUM_, ParserVALUES_, ParserVIEW_, ParserVIRTUAL_, ParserWHEN_, ParserWHERE_, ParserWITH_, ParserWITHOUT_, ParserFIRST_VALUE_, ParserOVER_, ParserPARTITION_, ParserRANGE_, ParserPRECEDING_, ParserUNBOUNDED_, ParserCURRENT_, ParserFOLLOWING_, ParserCUME_DIST_, ParserDENSE_RANK_, ParserLAG_, ParserLAST_VALUE_, ParserLEAD_, ParserNTH_VALUE_, ParserNTILE_, ParserPERCENT_RANK_, ParserRANK_, ParserROW_NUMBER_, ParserGENERATED_, ParserALWAYS_, ParserSTORED_, ParserTRUE_, ParserFALSE_, ParserWINDOW_, ParserNULLS_, ParserFIRST_, ParserLAST_, ParserFILTER_, ParserGROUPS_, ParserEXCLUDE_, ParserIDENTIFIER, ParserNUMERIC_LITERAL, ParserBIND_PARAMETER, ParserSTRING_LITERAL, ParserBLOB_LITERAL:
{
p.SetState(1756)
p.expr(0)
}
p.SetState(1761)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1757)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1758)
p.expr(0)
}
p.SetState(1763)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
case ParserSTAR:
{
p.SetState(1764)
p.Match(ParserSTAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
{
p.SetState(1767)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IAggregate_function_invocationContext is an interface to support dynamic dispatch.
type IAggregate_function_invocationContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Aggregate_func() IAggregate_funcContext
OPEN_PAR() antlr.TerminalNode
CLOSE_PAR() antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
STAR() antlr.TerminalNode
Filter_clause() IFilter_clauseContext
DISTINCT_() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsAggregate_function_invocationContext differentiates from other interfaces.
IsAggregate_function_invocationContext()
}
type Aggregate_function_invocationContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyAggregate_function_invocationContext() *Aggregate_function_invocationContext {
var p = new(Aggregate_function_invocationContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_aggregate_function_invocation
return p
}
func InitEmptyAggregate_function_invocationContext(p *Aggregate_function_invocationContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_aggregate_function_invocation
}
func (*Aggregate_function_invocationContext) IsAggregate_function_invocationContext() {}
func NewAggregate_function_invocationContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Aggregate_function_invocationContext {
var p = new(Aggregate_function_invocationContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_aggregate_function_invocation
return p
}
func (s *Aggregate_function_invocationContext) GetParser() antlr.Parser { return s.parser }
func (s *Aggregate_function_invocationContext) Aggregate_func() IAggregate_funcContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAggregate_funcContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAggregate_funcContext)
}
func (s *Aggregate_function_invocationContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Aggregate_function_invocationContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Aggregate_function_invocationContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Aggregate_function_invocationContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Aggregate_function_invocationContext) STAR() antlr.TerminalNode {
return s.GetToken(ParserSTAR, 0)
}
func (s *Aggregate_function_invocationContext) Filter_clause() IFilter_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFilter_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFilter_clauseContext)
}
func (s *Aggregate_function_invocationContext) DISTINCT_() antlr.TerminalNode {
return s.GetToken(ParserDISTINCT_, 0)
}
func (s *Aggregate_function_invocationContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Aggregate_function_invocationContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Aggregate_function_invocationContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Aggregate_function_invocationContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Aggregate_function_invocationContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterAggregate_function_invocation(s)
}
}
func (s *Aggregate_function_invocationContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitAggregate_function_invocation(s)
}
}
func (s *Aggregate_function_invocationContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitAggregate_function_invocation(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Aggregate_function_invocation() (localctx IAggregate_function_invocationContext) {
localctx = NewAggregate_function_invocationContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 130, ParserRULE_aggregate_function_invocation)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1769)
p.Aggregate_func()
}
{
p.SetState(1770)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1783)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserOPEN_PAR, ParserPLUS, ParserMINUS, ParserTILDE, ParserABORT_, ParserACTION_, ParserADD_, ParserAFTER_, ParserALL_, ParserALTER_, ParserANALYZE_, ParserAND_, ParserAS_, ParserASC_, ParserATTACH_, ParserAUTOINCREMENT_, ParserBEFORE_, ParserBEGIN_, ParserBETWEEN_, ParserBY_, ParserCASCADE_, ParserCASE_, ParserCAST_, ParserCHECK_, ParserCOLLATE_, ParserCOLUMN_, ParserCOMMIT_, ParserCONFLICT_, ParserCONSTRAINT_, ParserCREATE_, ParserCROSS_, ParserCURRENT_DATE_, ParserCURRENT_TIME_, ParserCURRENT_TIMESTAMP_, ParserDATABASE_, ParserDEFAULT_, ParserDEFERRABLE_, ParserDEFERRED_, ParserDELETE_, ParserDESC_, ParserDETACH_, ParserDISTINCT_, ParserDROP_, ParserEACH_, ParserELSE_, ParserEND_, ParserESCAPE_, ParserEXCEPT_, ParserEXCLUSIVE_, ParserEXISTS_, ParserEXPLAIN_, ParserFAIL_, ParserFOR_, ParserFOREIGN_, ParserFROM_, ParserFULL_, ParserGLOB_, ParserGROUP_, ParserHAVING_, ParserIF_, ParserIGNORE_, ParserIMMEDIATE_, ParserIN_, ParserINDEX_, ParserINDEXED_, ParserINITIALLY_, ParserINNER_, ParserINSERT_, ParserINSTEAD_, ParserINTERSECT_, ParserINTO_, ParserIS_, ParserISNULL_, ParserJOIN_, ParserKEY_, ParserLEFT_, ParserLIKE_, ParserLIMIT_, ParserMATCH_, ParserNATURAL_, ParserNO_, ParserNOT_, ParserNOTNULL_, ParserNULL_, ParserOF_, ParserOFFSET_, ParserON_, ParserOR_, ParserORDER_, ParserOUTER_, ParserPLAN_, ParserPRAGMA_, ParserPRIMARY_, ParserQUERY_, ParserRAISE_, ParserRECURSIVE_, ParserREFERENCES_, ParserREGEXP_, ParserREINDEX_, ParserRELEASE_, ParserRENAME_, ParserREPLACE_, ParserRESTRICT_, ParserRIGHT_, ParserROLLBACK_, ParserROW_, ParserROWS_, ParserSAVEPOINT_, ParserSELECT_, ParserSET_, ParserTABLE_, ParserTEMP_, ParserTEMPORARY_, ParserTHEN_, ParserTO_, ParserTRANSACTION_, ParserTRIGGER_, ParserUNION_, ParserUNIQUE_, ParserUPDATE_, ParserUSING_, ParserVACUUM_, ParserVALUES_, ParserVIEW_, ParserVIRTUAL_, ParserWHEN_, ParserWHERE_, ParserWITH_, ParserWITHOUT_, ParserFIRST_VALUE_, ParserOVER_, ParserPARTITION_, ParserRANGE_, ParserPRECEDING_, ParserUNBOUNDED_, ParserCURRENT_, ParserFOLLOWING_, ParserCUME_DIST_, ParserDENSE_RANK_, ParserLAG_, ParserLAST_VALUE_, ParserLEAD_, ParserNTH_VALUE_, ParserNTILE_, ParserPERCENT_RANK_, ParserRANK_, ParserROW_NUMBER_, ParserGENERATED_, ParserALWAYS_, ParserSTORED_, ParserTRUE_, ParserFALSE_, ParserWINDOW_, ParserNULLS_, ParserFIRST_, ParserLAST_, ParserFILTER_, ParserGROUPS_, ParserEXCLUDE_, ParserIDENTIFIER, ParserNUMERIC_LITERAL, ParserBIND_PARAMETER, ParserSTRING_LITERAL, ParserBLOB_LITERAL:
p.SetState(1772)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 260, p.GetParserRuleContext()) == 1 {
{
p.SetState(1771)
p.Match(ParserDISTINCT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1774)
p.expr(0)
}
p.SetState(1779)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1775)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1776)
p.expr(0)
}
p.SetState(1781)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
case ParserSTAR:
{
p.SetState(1782)
p.Match(ParserSTAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserCLOSE_PAR:
default:
}
{
p.SetState(1785)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1787)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserFILTER_ {
{
p.SetState(1786)
p.Filter_clause()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IWindow_function_invocationContext is an interface to support dynamic dispatch.
type IWindow_function_invocationContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Window_function() IWindow_functionContext
OPEN_PAR() antlr.TerminalNode
CLOSE_PAR() antlr.TerminalNode
OVER_() antlr.TerminalNode
Window_defn() IWindow_defnContext
Window_name() IWindow_nameContext
AllExpr() []IExprContext
Expr(i int) IExprContext
STAR() antlr.TerminalNode
Filter_clause() IFilter_clauseContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsWindow_function_invocationContext differentiates from other interfaces.
IsWindow_function_invocationContext()
}
type Window_function_invocationContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyWindow_function_invocationContext() *Window_function_invocationContext {
var p = new(Window_function_invocationContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_window_function_invocation
return p
}
func InitEmptyWindow_function_invocationContext(p *Window_function_invocationContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_window_function_invocation
}
func (*Window_function_invocationContext) IsWindow_function_invocationContext() {}
func NewWindow_function_invocationContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Window_function_invocationContext {
var p = new(Window_function_invocationContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_window_function_invocation
return p
}
func (s *Window_function_invocationContext) GetParser() antlr.Parser { return s.parser }
func (s *Window_function_invocationContext) Window_function() IWindow_functionContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IWindow_functionContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IWindow_functionContext)
}
func (s *Window_function_invocationContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Window_function_invocationContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Window_function_invocationContext) OVER_() antlr.TerminalNode {
return s.GetToken(ParserOVER_, 0)
}
func (s *Window_function_invocationContext) Window_defn() IWindow_defnContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IWindow_defnContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IWindow_defnContext)
}
func (s *Window_function_invocationContext) Window_name() IWindow_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IWindow_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IWindow_nameContext)
}
func (s *Window_function_invocationContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Window_function_invocationContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Window_function_invocationContext) STAR() antlr.TerminalNode {
return s.GetToken(ParserSTAR, 0)
}
func (s *Window_function_invocationContext) Filter_clause() IFilter_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFilter_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFilter_clauseContext)
}
func (s *Window_function_invocationContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Window_function_invocationContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Window_function_invocationContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Window_function_invocationContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Window_function_invocationContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterWindow_function_invocation(s)
}
}
func (s *Window_function_invocationContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitWindow_function_invocation(s)
}
}
func (s *Window_function_invocationContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitWindow_function_invocation(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Window_function_invocation() (localctx IWindow_function_invocationContext) {
localctx = NewWindow_function_invocationContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 132, ParserRULE_window_function_invocation)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1789)
p.Window_function()
}
{
p.SetState(1790)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1800)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserOPEN_PAR, ParserPLUS, ParserMINUS, ParserTILDE, ParserABORT_, ParserACTION_, ParserADD_, ParserAFTER_, ParserALL_, ParserALTER_, ParserANALYZE_, ParserAND_, ParserAS_, ParserASC_, ParserATTACH_, ParserAUTOINCREMENT_, ParserBEFORE_, ParserBEGIN_, ParserBETWEEN_, ParserBY_, ParserCASCADE_, ParserCASE_, ParserCAST_, ParserCHECK_, ParserCOLLATE_, ParserCOLUMN_, ParserCOMMIT_, ParserCONFLICT_, ParserCONSTRAINT_, ParserCREATE_, ParserCROSS_, ParserCURRENT_DATE_, ParserCURRENT_TIME_, ParserCURRENT_TIMESTAMP_, ParserDATABASE_, ParserDEFAULT_, ParserDEFERRABLE_, ParserDEFERRED_, ParserDELETE_, ParserDESC_, ParserDETACH_, ParserDISTINCT_, ParserDROP_, ParserEACH_, ParserELSE_, ParserEND_, ParserESCAPE_, ParserEXCEPT_, ParserEXCLUSIVE_, ParserEXISTS_, ParserEXPLAIN_, ParserFAIL_, ParserFOR_, ParserFOREIGN_, ParserFROM_, ParserFULL_, ParserGLOB_, ParserGROUP_, ParserHAVING_, ParserIF_, ParserIGNORE_, ParserIMMEDIATE_, ParserIN_, ParserINDEX_, ParserINDEXED_, ParserINITIALLY_, ParserINNER_, ParserINSERT_, ParserINSTEAD_, ParserINTERSECT_, ParserINTO_, ParserIS_, ParserISNULL_, ParserJOIN_, ParserKEY_, ParserLEFT_, ParserLIKE_, ParserLIMIT_, ParserMATCH_, ParserNATURAL_, ParserNO_, ParserNOT_, ParserNOTNULL_, ParserNULL_, ParserOF_, ParserOFFSET_, ParserON_, ParserOR_, ParserORDER_, ParserOUTER_, ParserPLAN_, ParserPRAGMA_, ParserPRIMARY_, ParserQUERY_, ParserRAISE_, ParserRECURSIVE_, ParserREFERENCES_, ParserREGEXP_, ParserREINDEX_, ParserRELEASE_, ParserRENAME_, ParserREPLACE_, ParserRESTRICT_, ParserRIGHT_, ParserROLLBACK_, ParserROW_, ParserROWS_, ParserSAVEPOINT_, ParserSELECT_, ParserSET_, ParserTABLE_, ParserTEMP_, ParserTEMPORARY_, ParserTHEN_, ParserTO_, ParserTRANSACTION_, ParserTRIGGER_, ParserUNION_, ParserUNIQUE_, ParserUPDATE_, ParserUSING_, ParserVACUUM_, ParserVALUES_, ParserVIEW_, ParserVIRTUAL_, ParserWHEN_, ParserWHERE_, ParserWITH_, ParserWITHOUT_, ParserFIRST_VALUE_, ParserOVER_, ParserPARTITION_, ParserRANGE_, ParserPRECEDING_, ParserUNBOUNDED_, ParserCURRENT_, ParserFOLLOWING_, ParserCUME_DIST_, ParserDENSE_RANK_, ParserLAG_, ParserLAST_VALUE_, ParserLEAD_, ParserNTH_VALUE_, ParserNTILE_, ParserPERCENT_RANK_, ParserRANK_, ParserROW_NUMBER_, ParserGENERATED_, ParserALWAYS_, ParserSTORED_, ParserTRUE_, ParserFALSE_, ParserWINDOW_, ParserNULLS_, ParserFIRST_, ParserLAST_, ParserFILTER_, ParserGROUPS_, ParserEXCLUDE_, ParserIDENTIFIER, ParserNUMERIC_LITERAL, ParserBIND_PARAMETER, ParserSTRING_LITERAL, ParserBLOB_LITERAL:
{
p.SetState(1791)
p.expr(0)
}
p.SetState(1796)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1792)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1793)
p.expr(0)
}
p.SetState(1798)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
case ParserSTAR:
{
p.SetState(1799)
p.Match(ParserSTAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserCLOSE_PAR:
default:
}
{
p.SetState(1802)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1804)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserFILTER_ {
{
p.SetState(1803)
p.Filter_clause()
}
}
{
p.SetState(1806)
p.Match(ParserOVER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1809)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 267, p.GetParserRuleContext()) {
case 1:
{
p.SetState(1807)
p.Window_defn()
}
case 2:
{
p.SetState(1808)
p.Window_name()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICommon_table_stmtContext is an interface to support dynamic dispatch.
type ICommon_table_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
WITH_() antlr.TerminalNode
AllCommon_table_expression() []ICommon_table_expressionContext
Common_table_expression(i int) ICommon_table_expressionContext
RECURSIVE_() antlr.TerminalNode
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsCommon_table_stmtContext differentiates from other interfaces.
IsCommon_table_stmtContext()
}
type Common_table_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyCommon_table_stmtContext() *Common_table_stmtContext {
var p = new(Common_table_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_common_table_stmt
return p
}
func InitEmptyCommon_table_stmtContext(p *Common_table_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_common_table_stmt
}
func (*Common_table_stmtContext) IsCommon_table_stmtContext() {}
func NewCommon_table_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Common_table_stmtContext {
var p = new(Common_table_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_common_table_stmt
return p
}
func (s *Common_table_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Common_table_stmtContext) WITH_() antlr.TerminalNode {
return s.GetToken(ParserWITH_, 0)
}
func (s *Common_table_stmtContext) AllCommon_table_expression() []ICommon_table_expressionContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(ICommon_table_expressionContext); ok {
len++
}
}
tst := make([]ICommon_table_expressionContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(ICommon_table_expressionContext); ok {
tst[i] = t.(ICommon_table_expressionContext)
i++
}
}
return tst
}
func (s *Common_table_stmtContext) Common_table_expression(i int) ICommon_table_expressionContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICommon_table_expressionContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(ICommon_table_expressionContext)
}
func (s *Common_table_stmtContext) RECURSIVE_() antlr.TerminalNode {
return s.GetToken(ParserRECURSIVE_, 0)
}
func (s *Common_table_stmtContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Common_table_stmtContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Common_table_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Common_table_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Common_table_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCommon_table_stmt(s)
}
}
func (s *Common_table_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCommon_table_stmt(s)
}
}
func (s *Common_table_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCommon_table_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Common_table_stmt() (localctx ICommon_table_stmtContext) {
localctx = NewCommon_table_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 134, ParserRULE_common_table_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1811)
p.Match(ParserWITH_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1813)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 268, p.GetParserRuleContext()) == 1 {
{
p.SetState(1812)
p.Match(ParserRECURSIVE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
} else if p.HasError() { // JIM
goto errorExit
}
{
p.SetState(1815)
p.Common_table_expression()
}
p.SetState(1820)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1816)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1817)
p.Common_table_expression()
}
p.SetState(1822)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IOrder_by_stmtContext is an interface to support dynamic dispatch.
type IOrder_by_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ORDER_() antlr.TerminalNode
BY_() antlr.TerminalNode
AllOrdering_term() []IOrdering_termContext
Ordering_term(i int) IOrdering_termContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsOrder_by_stmtContext differentiates from other interfaces.
IsOrder_by_stmtContext()
}
type Order_by_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyOrder_by_stmtContext() *Order_by_stmtContext {
var p = new(Order_by_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_order_by_stmt
return p
}
func InitEmptyOrder_by_stmtContext(p *Order_by_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_order_by_stmt
}
func (*Order_by_stmtContext) IsOrder_by_stmtContext() {}
func NewOrder_by_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Order_by_stmtContext {
var p = new(Order_by_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_order_by_stmt
return p
}
func (s *Order_by_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Order_by_stmtContext) ORDER_() antlr.TerminalNode {
return s.GetToken(ParserORDER_, 0)
}
func (s *Order_by_stmtContext) BY_() antlr.TerminalNode {
return s.GetToken(ParserBY_, 0)
}
func (s *Order_by_stmtContext) AllOrdering_term() []IOrdering_termContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IOrdering_termContext); ok {
len++
}
}
tst := make([]IOrdering_termContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IOrdering_termContext); ok {
tst[i] = t.(IOrdering_termContext)
i++
}
}
return tst
}
func (s *Order_by_stmtContext) Ordering_term(i int) IOrdering_termContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOrdering_termContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IOrdering_termContext)
}
func (s *Order_by_stmtContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Order_by_stmtContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Order_by_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Order_by_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Order_by_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterOrder_by_stmt(s)
}
}
func (s *Order_by_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitOrder_by_stmt(s)
}
}
func (s *Order_by_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitOrder_by_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Order_by_stmt() (localctx IOrder_by_stmtContext) {
localctx = NewOrder_by_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 136, ParserRULE_order_by_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1823)
p.Match(ParserORDER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1824)
p.Match(ParserBY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1825)
p.Ordering_term()
}
p.SetState(1830)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(1826)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1827)
p.Ordering_term()
}
p.SetState(1832)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ILimit_stmtContext is an interface to support dynamic dispatch.
type ILimit_stmtContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
LIMIT_() antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
OFFSET_() antlr.TerminalNode
COMMA() antlr.TerminalNode
// IsLimit_stmtContext differentiates from other interfaces.
IsLimit_stmtContext()
}
type Limit_stmtContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyLimit_stmtContext() *Limit_stmtContext {
var p = new(Limit_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_limit_stmt
return p
}
func InitEmptyLimit_stmtContext(p *Limit_stmtContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_limit_stmt
}
func (*Limit_stmtContext) IsLimit_stmtContext() {}
func NewLimit_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Limit_stmtContext {
var p = new(Limit_stmtContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_limit_stmt
return p
}
func (s *Limit_stmtContext) GetParser() antlr.Parser { return s.parser }
func (s *Limit_stmtContext) LIMIT_() antlr.TerminalNode {
return s.GetToken(ParserLIMIT_, 0)
}
func (s *Limit_stmtContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Limit_stmtContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Limit_stmtContext) OFFSET_() antlr.TerminalNode {
return s.GetToken(ParserOFFSET_, 0)
}
func (s *Limit_stmtContext) COMMA() antlr.TerminalNode {
return s.GetToken(ParserCOMMA, 0)
}
func (s *Limit_stmtContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Limit_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Limit_stmtContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterLimit_stmt(s)
}
}
func (s *Limit_stmtContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitLimit_stmt(s)
}
}
func (s *Limit_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitLimit_stmt(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Limit_stmt() (localctx ILimit_stmtContext) {
localctx = NewLimit_stmtContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 138, ParserRULE_limit_stmt)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1833)
p.Match(ParserLIMIT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1834)
p.expr(0)
}
p.SetState(1837)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserCOMMA || _la == ParserOFFSET_ {
{
p.SetState(1835)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserCOMMA || _la == ParserOFFSET_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
{
p.SetState(1836)
p.expr(0)
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IOrdering_termContext is an interface to support dynamic dispatch.
type IOrdering_termContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Expr() IExprContext
COLLATE_() antlr.TerminalNode
Collation_name() ICollation_nameContext
Asc_desc() IAsc_descContext
NULLS_() antlr.TerminalNode
FIRST_() antlr.TerminalNode
LAST_() antlr.TerminalNode
// IsOrdering_termContext differentiates from other interfaces.
IsOrdering_termContext()
}
type Ordering_termContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyOrdering_termContext() *Ordering_termContext {
var p = new(Ordering_termContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_ordering_term
return p
}
func InitEmptyOrdering_termContext(p *Ordering_termContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_ordering_term
}
func (*Ordering_termContext) IsOrdering_termContext() {}
func NewOrdering_termContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Ordering_termContext {
var p = new(Ordering_termContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_ordering_term
return p
}
func (s *Ordering_termContext) GetParser() antlr.Parser { return s.parser }
func (s *Ordering_termContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Ordering_termContext) COLLATE_() antlr.TerminalNode {
return s.GetToken(ParserCOLLATE_, 0)
}
func (s *Ordering_termContext) Collation_name() ICollation_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ICollation_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ICollation_nameContext)
}
func (s *Ordering_termContext) Asc_desc() IAsc_descContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAsc_descContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAsc_descContext)
}
func (s *Ordering_termContext) NULLS_() antlr.TerminalNode {
return s.GetToken(ParserNULLS_, 0)
}
func (s *Ordering_termContext) FIRST_() antlr.TerminalNode {
return s.GetToken(ParserFIRST_, 0)
}
func (s *Ordering_termContext) LAST_() antlr.TerminalNode {
return s.GetToken(ParserLAST_, 0)
}
func (s *Ordering_termContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Ordering_termContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Ordering_termContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterOrdering_term(s)
}
}
func (s *Ordering_termContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitOrdering_term(s)
}
}
func (s *Ordering_termContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitOrdering_term(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Ordering_term() (localctx IOrdering_termContext) {
localctx = NewOrdering_termContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 140, ParserRULE_ordering_term)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1839)
p.expr(0)
}
p.SetState(1842)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserCOLLATE_ {
{
p.SetState(1840)
p.Match(ParserCOLLATE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1841)
p.Collation_name()
}
}
p.SetState(1845)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserASC_ || _la == ParserDESC_ {
{
p.SetState(1844)
p.Asc_desc()
}
}
p.SetState(1849)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserNULLS_ {
{
p.SetState(1847)
p.Match(ParserNULLS_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1848)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserFIRST_ || _la == ParserLAST_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IAsc_descContext is an interface to support dynamic dispatch.
type IAsc_descContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ASC_() antlr.TerminalNode
DESC_() antlr.TerminalNode
// IsAsc_descContext differentiates from other interfaces.
IsAsc_descContext()
}
type Asc_descContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyAsc_descContext() *Asc_descContext {
var p = new(Asc_descContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_asc_desc
return p
}
func InitEmptyAsc_descContext(p *Asc_descContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_asc_desc
}
func (*Asc_descContext) IsAsc_descContext() {}
func NewAsc_descContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Asc_descContext {
var p = new(Asc_descContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_asc_desc
return p
}
func (s *Asc_descContext) GetParser() antlr.Parser { return s.parser }
func (s *Asc_descContext) ASC_() antlr.TerminalNode {
return s.GetToken(ParserASC_, 0)
}
func (s *Asc_descContext) DESC_() antlr.TerminalNode {
return s.GetToken(ParserDESC_, 0)
}
func (s *Asc_descContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Asc_descContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Asc_descContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterAsc_desc(s)
}
}
func (s *Asc_descContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitAsc_desc(s)
}
}
func (s *Asc_descContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitAsc_desc(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Asc_desc() (localctx IAsc_descContext) {
localctx = NewAsc_descContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 142, ParserRULE_asc_desc)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1851)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserASC_ || _la == ParserDESC_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IFrame_leftContext is an interface to support dynamic dispatch.
type IFrame_leftContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Expr() IExprContext
PRECEDING_() antlr.TerminalNode
FOLLOWING_() antlr.TerminalNode
CURRENT_() antlr.TerminalNode
ROW_() antlr.TerminalNode
UNBOUNDED_() antlr.TerminalNode
// IsFrame_leftContext differentiates from other interfaces.
IsFrame_leftContext()
}
type Frame_leftContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyFrame_leftContext() *Frame_leftContext {
var p = new(Frame_leftContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_frame_left
return p
}
func InitEmptyFrame_leftContext(p *Frame_leftContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_frame_left
}
func (*Frame_leftContext) IsFrame_leftContext() {}
func NewFrame_leftContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Frame_leftContext {
var p = new(Frame_leftContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_frame_left
return p
}
func (s *Frame_leftContext) GetParser() antlr.Parser { return s.parser }
func (s *Frame_leftContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Frame_leftContext) PRECEDING_() antlr.TerminalNode {
return s.GetToken(ParserPRECEDING_, 0)
}
func (s *Frame_leftContext) FOLLOWING_() antlr.TerminalNode {
return s.GetToken(ParserFOLLOWING_, 0)
}
func (s *Frame_leftContext) CURRENT_() antlr.TerminalNode {
return s.GetToken(ParserCURRENT_, 0)
}
func (s *Frame_leftContext) ROW_() antlr.TerminalNode {
return s.GetToken(ParserROW_, 0)
}
func (s *Frame_leftContext) UNBOUNDED_() antlr.TerminalNode {
return s.GetToken(ParserUNBOUNDED_, 0)
}
func (s *Frame_leftContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Frame_leftContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Frame_leftContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterFrame_left(s)
}
}
func (s *Frame_leftContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitFrame_left(s)
}
}
func (s *Frame_leftContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitFrame_left(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Frame_left() (localctx IFrame_leftContext) {
localctx = NewFrame_leftContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 144, ParserRULE_frame_left)
p.SetState(1863)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 275, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1853)
p.expr(0)
}
{
p.SetState(1854)
p.Match(ParserPRECEDING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(1856)
p.expr(0)
}
{
p.SetState(1857)
p.Match(ParserFOLLOWING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 3:
p.EnterOuterAlt(localctx, 3)
{
p.SetState(1859)
p.Match(ParserCURRENT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1860)
p.Match(ParserROW_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 4:
p.EnterOuterAlt(localctx, 4)
{
p.SetState(1861)
p.Match(ParserUNBOUNDED_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1862)
p.Match(ParserPRECEDING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IFrame_rightContext is an interface to support dynamic dispatch.
type IFrame_rightContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Expr() IExprContext
PRECEDING_() antlr.TerminalNode
FOLLOWING_() antlr.TerminalNode
CURRENT_() antlr.TerminalNode
ROW_() antlr.TerminalNode
UNBOUNDED_() antlr.TerminalNode
// IsFrame_rightContext differentiates from other interfaces.
IsFrame_rightContext()
}
type Frame_rightContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyFrame_rightContext() *Frame_rightContext {
var p = new(Frame_rightContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_frame_right
return p
}
func InitEmptyFrame_rightContext(p *Frame_rightContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_frame_right
}
func (*Frame_rightContext) IsFrame_rightContext() {}
func NewFrame_rightContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Frame_rightContext {
var p = new(Frame_rightContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_frame_right
return p
}
func (s *Frame_rightContext) GetParser() antlr.Parser { return s.parser }
func (s *Frame_rightContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Frame_rightContext) PRECEDING_() antlr.TerminalNode {
return s.GetToken(ParserPRECEDING_, 0)
}
func (s *Frame_rightContext) FOLLOWING_() antlr.TerminalNode {
return s.GetToken(ParserFOLLOWING_, 0)
}
func (s *Frame_rightContext) CURRENT_() antlr.TerminalNode {
return s.GetToken(ParserCURRENT_, 0)
}
func (s *Frame_rightContext) ROW_() antlr.TerminalNode {
return s.GetToken(ParserROW_, 0)
}
func (s *Frame_rightContext) UNBOUNDED_() antlr.TerminalNode {
return s.GetToken(ParserUNBOUNDED_, 0)
}
func (s *Frame_rightContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Frame_rightContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Frame_rightContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterFrame_right(s)
}
}
func (s *Frame_rightContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitFrame_right(s)
}
}
func (s *Frame_rightContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitFrame_right(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Frame_right() (localctx IFrame_rightContext) {
localctx = NewFrame_rightContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 146, ParserRULE_frame_right)
p.SetState(1875)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 276, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1865)
p.expr(0)
}
{
p.SetState(1866)
p.Match(ParserPRECEDING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(1868)
p.expr(0)
}
{
p.SetState(1869)
p.Match(ParserFOLLOWING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 3:
p.EnterOuterAlt(localctx, 3)
{
p.SetState(1871)
p.Match(ParserCURRENT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1872)
p.Match(ParserROW_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 4:
p.EnterOuterAlt(localctx, 4)
{
p.SetState(1873)
p.Match(ParserUNBOUNDED_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1874)
p.Match(ParserFOLLOWING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IFrame_singleContext is an interface to support dynamic dispatch.
type IFrame_singleContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Expr() IExprContext
PRECEDING_() antlr.TerminalNode
UNBOUNDED_() antlr.TerminalNode
CURRENT_() antlr.TerminalNode
ROW_() antlr.TerminalNode
// IsFrame_singleContext differentiates from other interfaces.
IsFrame_singleContext()
}
type Frame_singleContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyFrame_singleContext() *Frame_singleContext {
var p = new(Frame_singleContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_frame_single
return p
}
func InitEmptyFrame_singleContext(p *Frame_singleContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_frame_single
}
func (*Frame_singleContext) IsFrame_singleContext() {}
func NewFrame_singleContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Frame_singleContext {
var p = new(Frame_singleContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_frame_single
return p
}
func (s *Frame_singleContext) GetParser() antlr.Parser { return s.parser }
func (s *Frame_singleContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Frame_singleContext) PRECEDING_() antlr.TerminalNode {
return s.GetToken(ParserPRECEDING_, 0)
}
func (s *Frame_singleContext) UNBOUNDED_() antlr.TerminalNode {
return s.GetToken(ParserUNBOUNDED_, 0)
}
func (s *Frame_singleContext) CURRENT_() antlr.TerminalNode {
return s.GetToken(ParserCURRENT_, 0)
}
func (s *Frame_singleContext) ROW_() antlr.TerminalNode {
return s.GetToken(ParserROW_, 0)
}
func (s *Frame_singleContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Frame_singleContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Frame_singleContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterFrame_single(s)
}
}
func (s *Frame_singleContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitFrame_single(s)
}
}
func (s *Frame_singleContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitFrame_single(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Frame_single() (localctx IFrame_singleContext) {
localctx = NewFrame_singleContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 148, ParserRULE_frame_single)
p.SetState(1884)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 277, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1877)
p.expr(0)
}
{
p.SetState(1878)
p.Match(ParserPRECEDING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(1880)
p.Match(ParserUNBOUNDED_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1881)
p.Match(ParserPRECEDING_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case 3:
p.EnterOuterAlt(localctx, 3)
{
p.SetState(1882)
p.Match(ParserCURRENT_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1883)
p.Match(ParserROW_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IWindow_functionContext is an interface to support dynamic dispatch.
type IWindow_functionContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
AllOPEN_PAR() []antlr.TerminalNode
OPEN_PAR(i int) antlr.TerminalNode
Expr() IExprContext
AllCLOSE_PAR() []antlr.TerminalNode
CLOSE_PAR(i int) antlr.TerminalNode
OVER_() antlr.TerminalNode
Order_by_expr_asc_desc() IOrder_by_expr_asc_descContext
FIRST_VALUE_() antlr.TerminalNode
LAST_VALUE_() antlr.TerminalNode
Partition_by() IPartition_byContext
Frame_clause() IFrame_clauseContext
CUME_DIST_() antlr.TerminalNode
PERCENT_RANK_() antlr.TerminalNode
Order_by_expr() IOrder_by_exprContext
DENSE_RANK_() antlr.TerminalNode
RANK_() antlr.TerminalNode
ROW_NUMBER_() antlr.TerminalNode
LAG_() antlr.TerminalNode
LEAD_() antlr.TerminalNode
Offset() IOffsetContext
Default_value() IDefault_valueContext
NTH_VALUE_() antlr.TerminalNode
COMMA() antlr.TerminalNode
Signed_number() ISigned_numberContext
NTILE_() antlr.TerminalNode
// IsWindow_functionContext differentiates from other interfaces.
IsWindow_functionContext()
}
type Window_functionContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyWindow_functionContext() *Window_functionContext {
var p = new(Window_functionContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_window_function
return p
}
func InitEmptyWindow_functionContext(p *Window_functionContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_window_function
}
func (*Window_functionContext) IsWindow_functionContext() {}
func NewWindow_functionContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Window_functionContext {
var p = new(Window_functionContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_window_function
return p
}
func (s *Window_functionContext) GetParser() antlr.Parser { return s.parser }
func (s *Window_functionContext) AllOPEN_PAR() []antlr.TerminalNode {
return s.GetTokens(ParserOPEN_PAR)
}
func (s *Window_functionContext) OPEN_PAR(i int) antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, i)
}
func (s *Window_functionContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Window_functionContext) AllCLOSE_PAR() []antlr.TerminalNode {
return s.GetTokens(ParserCLOSE_PAR)
}
func (s *Window_functionContext) CLOSE_PAR(i int) antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, i)
}
func (s *Window_functionContext) OVER_() antlr.TerminalNode {
return s.GetToken(ParserOVER_, 0)
}
func (s *Window_functionContext) Order_by_expr_asc_desc() IOrder_by_expr_asc_descContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOrder_by_expr_asc_descContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IOrder_by_expr_asc_descContext)
}
func (s *Window_functionContext) FIRST_VALUE_() antlr.TerminalNode {
return s.GetToken(ParserFIRST_VALUE_, 0)
}
func (s *Window_functionContext) LAST_VALUE_() antlr.TerminalNode {
return s.GetToken(ParserLAST_VALUE_, 0)
}
func (s *Window_functionContext) Partition_by() IPartition_byContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IPartition_byContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IPartition_byContext)
}
func (s *Window_functionContext) Frame_clause() IFrame_clauseContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IFrame_clauseContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IFrame_clauseContext)
}
func (s *Window_functionContext) CUME_DIST_() antlr.TerminalNode {
return s.GetToken(ParserCUME_DIST_, 0)
}
func (s *Window_functionContext) PERCENT_RANK_() antlr.TerminalNode {
return s.GetToken(ParserPERCENT_RANK_, 0)
}
func (s *Window_functionContext) Order_by_expr() IOrder_by_exprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOrder_by_exprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IOrder_by_exprContext)
}
func (s *Window_functionContext) DENSE_RANK_() antlr.TerminalNode {
return s.GetToken(ParserDENSE_RANK_, 0)
}
func (s *Window_functionContext) RANK_() antlr.TerminalNode {
return s.GetToken(ParserRANK_, 0)
}
func (s *Window_functionContext) ROW_NUMBER_() antlr.TerminalNode {
return s.GetToken(ParserROW_NUMBER_, 0)
}
func (s *Window_functionContext) LAG_() antlr.TerminalNode {
return s.GetToken(ParserLAG_, 0)
}
func (s *Window_functionContext) LEAD_() antlr.TerminalNode {
return s.GetToken(ParserLEAD_, 0)
}
func (s *Window_functionContext) Offset() IOffsetContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IOffsetContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IOffsetContext)
}
func (s *Window_functionContext) Default_value() IDefault_valueContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IDefault_valueContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IDefault_valueContext)
}
func (s *Window_functionContext) NTH_VALUE_() antlr.TerminalNode {
return s.GetToken(ParserNTH_VALUE_, 0)
}
func (s *Window_functionContext) COMMA() antlr.TerminalNode {
return s.GetToken(ParserCOMMA, 0)
}
func (s *Window_functionContext) Signed_number() ISigned_numberContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISigned_numberContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISigned_numberContext)
}
func (s *Window_functionContext) NTILE_() antlr.TerminalNode {
return s.GetToken(ParserNTILE_, 0)
}
func (s *Window_functionContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Window_functionContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Window_functionContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterWindow_function(s)
}
}
func (s *Window_functionContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitWindow_function(s)
}
}
func (s *Window_functionContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitWindow_function(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Window_function() (localctx IWindow_functionContext) {
localctx = NewWindow_functionContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 150, ParserRULE_window_function)
var _la int
p.SetState(1971)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserFIRST_VALUE_, ParserLAST_VALUE_:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1886)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserFIRST_VALUE_ || _la == ParserLAST_VALUE_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
{
p.SetState(1887)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1888)
p.expr(0)
}
{
p.SetState(1889)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1890)
p.Match(ParserOVER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1891)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1893)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserPARTITION_ {
{
p.SetState(1892)
p.Partition_by()
}
}
{
p.SetState(1895)
p.Order_by_expr_asc_desc()
}
p.SetState(1897)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if (int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&2251799880794113) != 0 {
{
p.SetState(1896)
p.Frame_clause()
}
}
{
p.SetState(1899)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserCUME_DIST_, ParserPERCENT_RANK_:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(1901)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserCUME_DIST_ || _la == ParserPERCENT_RANK_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
{
p.SetState(1902)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1903)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1904)
p.Match(ParserOVER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1905)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1907)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserPARTITION_ {
{
p.SetState(1906)
p.Partition_by()
}
}
p.SetState(1910)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserORDER_ {
{
p.SetState(1909)
p.Order_by_expr()
}
}
{
p.SetState(1912)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserDENSE_RANK_, ParserRANK_, ParserROW_NUMBER_:
p.EnterOuterAlt(localctx, 3)
{
p.SetState(1913)
_la = p.GetTokenStream().LA(1)
if !((int64((_la-160)) & ^0x3f) == 0 && ((int64(1)<<(_la-160))&385) != 0) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
{
p.SetState(1914)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1915)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1916)
p.Match(ParserOVER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1917)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1919)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserPARTITION_ {
{
p.SetState(1918)
p.Partition_by()
}
}
{
p.SetState(1921)
p.Order_by_expr_asc_desc()
}
{
p.SetState(1922)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserLAG_, ParserLEAD_:
p.EnterOuterAlt(localctx, 4)
{
p.SetState(1924)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserLAG_ || _la == ParserLEAD_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
{
p.SetState(1925)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1926)
p.expr(0)
}
p.SetState(1928)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 283, p.GetParserRuleContext()) == 1 {
{
p.SetState(1927)
p.Offset()
}
} else if p.HasError() { // JIM
goto errorExit
}
p.SetState(1931)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserCOMMA {
{
p.SetState(1930)
p.Default_value()
}
}
{
p.SetState(1933)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1934)
p.Match(ParserOVER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1935)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1937)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserPARTITION_ {
{
p.SetState(1936)
p.Partition_by()
}
}
{
p.SetState(1939)
p.Order_by_expr_asc_desc()
}
{
p.SetState(1940)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserNTH_VALUE_:
p.EnterOuterAlt(localctx, 5)
{
p.SetState(1942)
p.Match(ParserNTH_VALUE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1943)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1944)
p.expr(0)
}
{
p.SetState(1945)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1946)
p.Signed_number()
}
{
p.SetState(1947)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1948)
p.Match(ParserOVER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1949)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1951)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserPARTITION_ {
{
p.SetState(1950)
p.Partition_by()
}
}
{
p.SetState(1953)
p.Order_by_expr_asc_desc()
}
p.SetState(1955)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if (int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&2251799880794113) != 0 {
{
p.SetState(1954)
p.Frame_clause()
}
}
{
p.SetState(1957)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserNTILE_:
p.EnterOuterAlt(localctx, 6)
{
p.SetState(1959)
p.Match(ParserNTILE_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1960)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1961)
p.expr(0)
}
{
p.SetState(1962)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1963)
p.Match(ParserOVER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1964)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1966)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserPARTITION_ {
{
p.SetState(1965)
p.Partition_by()
}
}
{
p.SetState(1968)
p.Order_by_expr_asc_desc()
}
{
p.SetState(1969)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IOffsetContext is an interface to support dynamic dispatch.
type IOffsetContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
COMMA() antlr.TerminalNode
Signed_number() ISigned_numberContext
// IsOffsetContext differentiates from other interfaces.
IsOffsetContext()
}
type OffsetContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyOffsetContext() *OffsetContext {
var p = new(OffsetContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_offset
return p
}
func InitEmptyOffsetContext(p *OffsetContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_offset
}
func (*OffsetContext) IsOffsetContext() {}
func NewOffsetContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *OffsetContext {
var p = new(OffsetContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_offset
return p
}
func (s *OffsetContext) GetParser() antlr.Parser { return s.parser }
func (s *OffsetContext) COMMA() antlr.TerminalNode {
return s.GetToken(ParserCOMMA, 0)
}
func (s *OffsetContext) Signed_number() ISigned_numberContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISigned_numberContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISigned_numberContext)
}
func (s *OffsetContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *OffsetContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *OffsetContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterOffset(s)
}
}
func (s *OffsetContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitOffset(s)
}
}
func (s *OffsetContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitOffset(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Offset() (localctx IOffsetContext) {
localctx = NewOffsetContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 152, ParserRULE_offset)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1973)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1974)
p.Signed_number()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IDefault_valueContext is an interface to support dynamic dispatch.
type IDefault_valueContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
COMMA() antlr.TerminalNode
Signed_number() ISigned_numberContext
// IsDefault_valueContext differentiates from other interfaces.
IsDefault_valueContext()
}
type Default_valueContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyDefault_valueContext() *Default_valueContext {
var p = new(Default_valueContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_default_value
return p
}
func InitEmptyDefault_valueContext(p *Default_valueContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_default_value
}
func (*Default_valueContext) IsDefault_valueContext() {}
func NewDefault_valueContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Default_valueContext {
var p = new(Default_valueContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_default_value
return p
}
func (s *Default_valueContext) GetParser() antlr.Parser { return s.parser }
func (s *Default_valueContext) COMMA() antlr.TerminalNode {
return s.GetToken(ParserCOMMA, 0)
}
func (s *Default_valueContext) Signed_number() ISigned_numberContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISigned_numberContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISigned_numberContext)
}
func (s *Default_valueContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Default_valueContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Default_valueContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterDefault_value(s)
}
}
func (s *Default_valueContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitDefault_value(s)
}
}
func (s *Default_valueContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitDefault_value(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Default_value() (localctx IDefault_valueContext) {
localctx = NewDefault_valueContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 154, ParserRULE_default_value)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1976)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1977)
p.Signed_number()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IPartition_byContext is an interface to support dynamic dispatch.
type IPartition_byContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
PARTITION_() antlr.TerminalNode
BY_() antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
// IsPartition_byContext differentiates from other interfaces.
IsPartition_byContext()
}
type Partition_byContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyPartition_byContext() *Partition_byContext {
var p = new(Partition_byContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_partition_by
return p
}
func InitEmptyPartition_byContext(p *Partition_byContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_partition_by
}
func (*Partition_byContext) IsPartition_byContext() {}
func NewPartition_byContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Partition_byContext {
var p = new(Partition_byContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_partition_by
return p
}
func (s *Partition_byContext) GetParser() antlr.Parser { return s.parser }
func (s *Partition_byContext) PARTITION_() antlr.TerminalNode {
return s.GetToken(ParserPARTITION_, 0)
}
func (s *Partition_byContext) BY_() antlr.TerminalNode {
return s.GetToken(ParserBY_, 0)
}
func (s *Partition_byContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Partition_byContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Partition_byContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Partition_byContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Partition_byContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterPartition_by(s)
}
}
func (s *Partition_byContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitPartition_by(s)
}
}
func (s *Partition_byContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitPartition_by(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Partition_by() (localctx IPartition_byContext) {
localctx = NewPartition_byContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 156, ParserRULE_partition_by)
var _alt int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1979)
p.Match(ParserPARTITION_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1980)
p.Match(ParserBY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1982)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_alt = 1
for ok := true; ok; ok = _alt != 2 && _alt != antlr.ATNInvalidAltNumber {
switch _alt {
case 1:
{
p.SetState(1981)
p.expr(0)
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
p.SetState(1984)
p.GetErrorHandler().Sync(p)
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 290, p.GetParserRuleContext())
if p.HasError() {
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IOrder_by_exprContext is an interface to support dynamic dispatch.
type IOrder_by_exprContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ORDER_() antlr.TerminalNode
BY_() antlr.TerminalNode
AllExpr() []IExprContext
Expr(i int) IExprContext
// IsOrder_by_exprContext differentiates from other interfaces.
IsOrder_by_exprContext()
}
type Order_by_exprContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyOrder_by_exprContext() *Order_by_exprContext {
var p = new(Order_by_exprContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_order_by_expr
return p
}
func InitEmptyOrder_by_exprContext(p *Order_by_exprContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_order_by_expr
}
func (*Order_by_exprContext) IsOrder_by_exprContext() {}
func NewOrder_by_exprContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Order_by_exprContext {
var p = new(Order_by_exprContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_order_by_expr
return p
}
func (s *Order_by_exprContext) GetParser() antlr.Parser { return s.parser }
func (s *Order_by_exprContext) ORDER_() antlr.TerminalNode {
return s.GetToken(ParserORDER_, 0)
}
func (s *Order_by_exprContext) BY_() antlr.TerminalNode {
return s.GetToken(ParserBY_, 0)
}
func (s *Order_by_exprContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Order_by_exprContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Order_by_exprContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Order_by_exprContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Order_by_exprContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterOrder_by_expr(s)
}
}
func (s *Order_by_exprContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitOrder_by_expr(s)
}
}
func (s *Order_by_exprContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitOrder_by_expr(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Order_by_expr() (localctx IOrder_by_exprContext) {
localctx = NewOrder_by_exprContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 158, ParserRULE_order_by_expr)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1986)
p.Match(ParserORDER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1987)
p.Match(ParserBY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
p.SetState(1989)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for ok := true; ok; ok = ((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&-33552632) != 0) || ((int64((_la-64)) & ^0x3f) == 0 && ((int64(1)<<(_la-64))&-1152921504606846977) != 0) || ((int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&4476578029606273023) != 0) {
{
p.SetState(1988)
p.expr(0)
}
p.SetState(1991)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IOrder_by_expr_asc_descContext is an interface to support dynamic dispatch.
type IOrder_by_expr_asc_descContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ORDER_() antlr.TerminalNode
BY_() antlr.TerminalNode
Expr_asc_desc() IExpr_asc_descContext
// IsOrder_by_expr_asc_descContext differentiates from other interfaces.
IsOrder_by_expr_asc_descContext()
}
type Order_by_expr_asc_descContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyOrder_by_expr_asc_descContext() *Order_by_expr_asc_descContext {
var p = new(Order_by_expr_asc_descContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_order_by_expr_asc_desc
return p
}
func InitEmptyOrder_by_expr_asc_descContext(p *Order_by_expr_asc_descContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_order_by_expr_asc_desc
}
func (*Order_by_expr_asc_descContext) IsOrder_by_expr_asc_descContext() {}
func NewOrder_by_expr_asc_descContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Order_by_expr_asc_descContext {
var p = new(Order_by_expr_asc_descContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_order_by_expr_asc_desc
return p
}
func (s *Order_by_expr_asc_descContext) GetParser() antlr.Parser { return s.parser }
func (s *Order_by_expr_asc_descContext) ORDER_() antlr.TerminalNode {
return s.GetToken(ParserORDER_, 0)
}
func (s *Order_by_expr_asc_descContext) BY_() antlr.TerminalNode {
return s.GetToken(ParserBY_, 0)
}
func (s *Order_by_expr_asc_descContext) Expr_asc_desc() IExpr_asc_descContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExpr_asc_descContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExpr_asc_descContext)
}
func (s *Order_by_expr_asc_descContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Order_by_expr_asc_descContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Order_by_expr_asc_descContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterOrder_by_expr_asc_desc(s)
}
}
func (s *Order_by_expr_asc_descContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitOrder_by_expr_asc_desc(s)
}
}
func (s *Order_by_expr_asc_descContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitOrder_by_expr_asc_desc(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Order_by_expr_asc_desc() (localctx IOrder_by_expr_asc_descContext) {
localctx = NewOrder_by_expr_asc_descContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 160, ParserRULE_order_by_expr_asc_desc)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1993)
p.Match(ParserORDER_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1994)
p.Match(ParserBY_)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(1995)
p.Expr_asc_desc()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IExpr_asc_descContext is an interface to support dynamic dispatch.
type IExpr_asc_descContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
AllExpr() []IExprContext
Expr(i int) IExprContext
AllAsc_desc() []IAsc_descContext
Asc_desc(i int) IAsc_descContext
AllCOMMA() []antlr.TerminalNode
COMMA(i int) antlr.TerminalNode
// IsExpr_asc_descContext differentiates from other interfaces.
IsExpr_asc_descContext()
}
type Expr_asc_descContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyExpr_asc_descContext() *Expr_asc_descContext {
var p = new(Expr_asc_descContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_expr_asc_desc
return p
}
func InitEmptyExpr_asc_descContext(p *Expr_asc_descContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_expr_asc_desc
}
func (*Expr_asc_descContext) IsExpr_asc_descContext() {}
func NewExpr_asc_descContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Expr_asc_descContext {
var p = new(Expr_asc_descContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_expr_asc_desc
return p
}
func (s *Expr_asc_descContext) GetParser() antlr.Parser { return s.parser }
func (s *Expr_asc_descContext) AllExpr() []IExprContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IExprContext); ok {
len++
}
}
tst := make([]IExprContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IExprContext); ok {
tst[i] = t.(IExprContext)
i++
}
}
return tst
}
func (s *Expr_asc_descContext) Expr(i int) IExprContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Expr_asc_descContext) AllAsc_desc() []IAsc_descContext {
children := s.GetChildren()
len := 0
for _, ctx := range children {
if _, ok := ctx.(IAsc_descContext); ok {
len++
}
}
tst := make([]IAsc_descContext, len)
i := 0
for _, ctx := range children {
if t, ok := ctx.(IAsc_descContext); ok {
tst[i] = t.(IAsc_descContext)
i++
}
}
return tst
}
func (s *Expr_asc_descContext) Asc_desc(i int) IAsc_descContext {
var t antlr.RuleContext
j := 0
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAsc_descContext); ok {
if j == i {
t = ctx.(antlr.RuleContext)
break
}
j++
}
}
if t == nil {
return nil
}
return t.(IAsc_descContext)
}
func (s *Expr_asc_descContext) AllCOMMA() []antlr.TerminalNode {
return s.GetTokens(ParserCOMMA)
}
func (s *Expr_asc_descContext) COMMA(i int) antlr.TerminalNode {
return s.GetToken(ParserCOMMA, i)
}
func (s *Expr_asc_descContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Expr_asc_descContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Expr_asc_descContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterExpr_asc_desc(s)
}
}
func (s *Expr_asc_descContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitExpr_asc_desc(s)
}
}
func (s *Expr_asc_descContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitExpr_asc_desc(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Expr_asc_desc() (localctx IExpr_asc_descContext) {
localctx = NewExpr_asc_descContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 162, ParserRULE_expr_asc_desc)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(1997)
p.expr(0)
}
p.SetState(1999)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserASC_ || _la == ParserDESC_ {
{
p.SetState(1998)
p.Asc_desc()
}
}
p.SetState(2008)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
for _la == ParserCOMMA {
{
p.SetState(2001)
p.Match(ParserCOMMA)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(2002)
p.expr(0)
}
p.SetState(2004)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
if _la == ParserASC_ || _la == ParserDESC_ {
{
p.SetState(2003)
p.Asc_desc()
}
}
p.SetState(2010)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
_la = p.GetTokenStream().LA(1)
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IInitial_selectContext is an interface to support dynamic dispatch.
type IInitial_selectContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Select_stmt() ISelect_stmtContext
// IsInitial_selectContext differentiates from other interfaces.
IsInitial_selectContext()
}
type Initial_selectContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyInitial_selectContext() *Initial_selectContext {
var p = new(Initial_selectContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_initial_select
return p
}
func InitEmptyInitial_selectContext(p *Initial_selectContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_initial_select
}
func (*Initial_selectContext) IsInitial_selectContext() {}
func NewInitial_selectContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Initial_selectContext {
var p = new(Initial_selectContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_initial_select
return p
}
func (s *Initial_selectContext) GetParser() antlr.Parser { return s.parser }
func (s *Initial_selectContext) Select_stmt() ISelect_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *Initial_selectContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Initial_selectContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Initial_selectContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterInitial_select(s)
}
}
func (s *Initial_selectContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitInitial_select(s)
}
}
func (s *Initial_selectContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitInitial_select(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Initial_select() (localctx IInitial_selectContext) {
localctx = NewInitial_selectContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 164, ParserRULE_initial_select)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2011)
p.Select_stmt()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IRecursive_selectContext is an interface to support dynamic dispatch.
type IRecursive_selectContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Select_stmt() ISelect_stmtContext
// IsRecursive_selectContext differentiates from other interfaces.
IsRecursive_selectContext()
}
type Recursive_selectContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyRecursive_selectContext() *Recursive_selectContext {
var p = new(Recursive_selectContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_recursive_select
return p
}
func InitEmptyRecursive_selectContext(p *Recursive_selectContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_recursive_select
}
func (*Recursive_selectContext) IsRecursive_selectContext() {}
func NewRecursive_selectContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Recursive_selectContext {
var p = new(Recursive_selectContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_recursive_select
return p
}
func (s *Recursive_selectContext) GetParser() antlr.Parser { return s.parser }
func (s *Recursive_selectContext) Select_stmt() ISelect_stmtContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(ISelect_stmtContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(ISelect_stmtContext)
}
func (s *Recursive_selectContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Recursive_selectContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Recursive_selectContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterRecursive_select(s)
}
}
func (s *Recursive_selectContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitRecursive_select(s)
}
}
func (s *Recursive_selectContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitRecursive_select(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Recursive_select() (localctx IRecursive_selectContext) {
localctx = NewRecursive_selectContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 166, ParserRULE_recursive_select)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2013)
p.Select_stmt()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IUnary_operatorContext is an interface to support dynamic dispatch.
type IUnary_operatorContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
MINUS() antlr.TerminalNode
PLUS() antlr.TerminalNode
TILDE() antlr.TerminalNode
NOT_() antlr.TerminalNode
// IsUnary_operatorContext differentiates from other interfaces.
IsUnary_operatorContext()
}
type Unary_operatorContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyUnary_operatorContext() *Unary_operatorContext {
var p = new(Unary_operatorContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_unary_operator
return p
}
func InitEmptyUnary_operatorContext(p *Unary_operatorContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_unary_operator
}
func (*Unary_operatorContext) IsUnary_operatorContext() {}
func NewUnary_operatorContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Unary_operatorContext {
var p = new(Unary_operatorContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_unary_operator
return p
}
func (s *Unary_operatorContext) GetParser() antlr.Parser { return s.parser }
func (s *Unary_operatorContext) MINUS() antlr.TerminalNode {
return s.GetToken(ParserMINUS, 0)
}
func (s *Unary_operatorContext) PLUS() antlr.TerminalNode {
return s.GetToken(ParserPLUS, 0)
}
func (s *Unary_operatorContext) TILDE() antlr.TerminalNode {
return s.GetToken(ParserTILDE, 0)
}
func (s *Unary_operatorContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *Unary_operatorContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Unary_operatorContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Unary_operatorContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterUnary_operator(s)
}
}
func (s *Unary_operatorContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitUnary_operator(s)
}
}
func (s *Unary_operatorContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitUnary_operator(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Unary_operator() (localctx IUnary_operatorContext) {
localctx = NewUnary_operatorContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 168, ParserRULE_unary_operator)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2015)
_la = p.GetTokenStream().LA(1)
if !(((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&1792) != 0) || _la == ParserNOT_) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IError_messageContext is an interface to support dynamic dispatch.
type IError_messageContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
STRING_LITERAL() antlr.TerminalNode
// IsError_messageContext differentiates from other interfaces.
IsError_messageContext()
}
type Error_messageContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyError_messageContext() *Error_messageContext {
var p = new(Error_messageContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_error_message
return p
}
func InitEmptyError_messageContext(p *Error_messageContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_error_message
}
func (*Error_messageContext) IsError_messageContext() {}
func NewError_messageContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Error_messageContext {
var p = new(Error_messageContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_error_message
return p
}
func (s *Error_messageContext) GetParser() antlr.Parser { return s.parser }
func (s *Error_messageContext) STRING_LITERAL() antlr.TerminalNode {
return s.GetToken(ParserSTRING_LITERAL, 0)
}
func (s *Error_messageContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Error_messageContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Error_messageContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterError_message(s)
}
}
func (s *Error_messageContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitError_message(s)
}
}
func (s *Error_messageContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitError_message(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Error_message() (localctx IError_messageContext) {
localctx = NewError_messageContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 170, ParserRULE_error_message)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2017)
p.Match(ParserSTRING_LITERAL)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IModule_argumentContext is an interface to support dynamic dispatch.
type IModule_argumentContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Expr() IExprContext
Column_def() IColumn_defContext
// IsModule_argumentContext differentiates from other interfaces.
IsModule_argumentContext()
}
type Module_argumentContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyModule_argumentContext() *Module_argumentContext {
var p = new(Module_argumentContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_module_argument
return p
}
func InitEmptyModule_argumentContext(p *Module_argumentContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_module_argument
}
func (*Module_argumentContext) IsModule_argumentContext() {}
func NewModule_argumentContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Module_argumentContext {
var p = new(Module_argumentContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_module_argument
return p
}
func (s *Module_argumentContext) GetParser() antlr.Parser { return s.parser }
func (s *Module_argumentContext) Expr() IExprContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IExprContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IExprContext)
}
func (s *Module_argumentContext) Column_def() IColumn_defContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IColumn_defContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IColumn_defContext)
}
func (s *Module_argumentContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Module_argumentContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Module_argumentContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterModule_argument(s)
}
}
func (s *Module_argumentContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitModule_argument(s)
}
}
func (s *Module_argumentContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitModule_argument(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Module_argument() (localctx IModule_argumentContext) {
localctx = NewModule_argumentContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 172, ParserRULE_module_argument)
p.SetState(2021)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 295, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2019)
p.expr(0)
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(2020)
p.Column_def()
}
case antlr.ATNInvalidAltNumber:
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IColumn_aliasContext is an interface to support dynamic dispatch.
type IColumn_aliasContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
IDENTIFIER() antlr.TerminalNode
STRING_LITERAL() antlr.TerminalNode
// IsColumn_aliasContext differentiates from other interfaces.
IsColumn_aliasContext()
}
type Column_aliasContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyColumn_aliasContext() *Column_aliasContext {
var p = new(Column_aliasContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_column_alias
return p
}
func InitEmptyColumn_aliasContext(p *Column_aliasContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_column_alias
}
func (*Column_aliasContext) IsColumn_aliasContext() {}
func NewColumn_aliasContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Column_aliasContext {
var p = new(Column_aliasContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_column_alias
return p
}
func (s *Column_aliasContext) GetParser() antlr.Parser { return s.parser }
func (s *Column_aliasContext) IDENTIFIER() antlr.TerminalNode {
return s.GetToken(ParserIDENTIFIER, 0)
}
func (s *Column_aliasContext) STRING_LITERAL() antlr.TerminalNode {
return s.GetToken(ParserSTRING_LITERAL, 0)
}
func (s *Column_aliasContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Column_aliasContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Column_aliasContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterColumn_alias(s)
}
}
func (s *Column_aliasContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitColumn_alias(s)
}
}
func (s *Column_aliasContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitColumn_alias(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Column_alias() (localctx IColumn_aliasContext) {
localctx = NewColumn_aliasContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 174, ParserRULE_column_alias)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2023)
_la = p.GetTokenStream().LA(1)
if !(_la == ParserIDENTIFIER || _la == ParserSTRING_LITERAL) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IKeywordContext is an interface to support dynamic dispatch.
type IKeywordContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
ABORT_() antlr.TerminalNode
ACTION_() antlr.TerminalNode
ADD_() antlr.TerminalNode
AFTER_() antlr.TerminalNode
ALL_() antlr.TerminalNode
ALTER_() antlr.TerminalNode
ANALYZE_() antlr.TerminalNode
AND_() antlr.TerminalNode
AS_() antlr.TerminalNode
ASC_() antlr.TerminalNode
ATTACH_() antlr.TerminalNode
AUTOINCREMENT_() antlr.TerminalNode
BEFORE_() antlr.TerminalNode
BEGIN_() antlr.TerminalNode
BETWEEN_() antlr.TerminalNode
BY_() antlr.TerminalNode
CASCADE_() antlr.TerminalNode
CASE_() antlr.TerminalNode
CAST_() antlr.TerminalNode
CHECK_() antlr.TerminalNode
COLLATE_() antlr.TerminalNode
COLUMN_() antlr.TerminalNode
COMMIT_() antlr.TerminalNode
CONFLICT_() antlr.TerminalNode
CONSTRAINT_() antlr.TerminalNode
CREATE_() antlr.TerminalNode
CROSS_() antlr.TerminalNode
CURRENT_DATE_() antlr.TerminalNode
CURRENT_TIME_() antlr.TerminalNode
CURRENT_TIMESTAMP_() antlr.TerminalNode
DATABASE_() antlr.TerminalNode
DEFAULT_() antlr.TerminalNode
DEFERRABLE_() antlr.TerminalNode
DEFERRED_() antlr.TerminalNode
DELETE_() antlr.TerminalNode
DESC_() antlr.TerminalNode
DETACH_() antlr.TerminalNode
DISTINCT_() antlr.TerminalNode
DROP_() antlr.TerminalNode
EACH_() antlr.TerminalNode
ELSE_() antlr.TerminalNode
END_() antlr.TerminalNode
ESCAPE_() antlr.TerminalNode
EXCEPT_() antlr.TerminalNode
EXCLUSIVE_() antlr.TerminalNode
EXISTS_() antlr.TerminalNode
EXPLAIN_() antlr.TerminalNode
FAIL_() antlr.TerminalNode
FOR_() antlr.TerminalNode
FOREIGN_() antlr.TerminalNode
FROM_() antlr.TerminalNode
FULL_() antlr.TerminalNode
GLOB_() antlr.TerminalNode
GROUP_() antlr.TerminalNode
HAVING_() antlr.TerminalNode
IF_() antlr.TerminalNode
IGNORE_() antlr.TerminalNode
IMMEDIATE_() antlr.TerminalNode
IN_() antlr.TerminalNode
INDEX_() antlr.TerminalNode
INDEXED_() antlr.TerminalNode
INITIALLY_() antlr.TerminalNode
INNER_() antlr.TerminalNode
INSERT_() antlr.TerminalNode
INSTEAD_() antlr.TerminalNode
INTERSECT_() antlr.TerminalNode
INTO_() antlr.TerminalNode
IS_() antlr.TerminalNode
ISNULL_() antlr.TerminalNode
JOIN_() antlr.TerminalNode
KEY_() antlr.TerminalNode
LEFT_() antlr.TerminalNode
LIKE_() antlr.TerminalNode
LIMIT_() antlr.TerminalNode
MATCH_() antlr.TerminalNode
NATURAL_() antlr.TerminalNode
NO_() antlr.TerminalNode
NOT_() antlr.TerminalNode
NOTNULL_() antlr.TerminalNode
NULL_() antlr.TerminalNode
OF_() antlr.TerminalNode
OFFSET_() antlr.TerminalNode
ON_() antlr.TerminalNode
OR_() antlr.TerminalNode
ORDER_() antlr.TerminalNode
OUTER_() antlr.TerminalNode
PLAN_() antlr.TerminalNode
PRAGMA_() antlr.TerminalNode
PRIMARY_() antlr.TerminalNode
QUERY_() antlr.TerminalNode
RAISE_() antlr.TerminalNode
RECURSIVE_() antlr.TerminalNode
REFERENCES_() antlr.TerminalNode
REGEXP_() antlr.TerminalNode
REINDEX_() antlr.TerminalNode
RELEASE_() antlr.TerminalNode
RENAME_() antlr.TerminalNode
REPLACE_() antlr.TerminalNode
RESTRICT_() antlr.TerminalNode
RIGHT_() antlr.TerminalNode
ROLLBACK_() antlr.TerminalNode
ROW_() antlr.TerminalNode
ROWS_() antlr.TerminalNode
SAVEPOINT_() antlr.TerminalNode
SELECT_() antlr.TerminalNode
SET_() antlr.TerminalNode
TABLE_() antlr.TerminalNode
TEMP_() antlr.TerminalNode
TEMPORARY_() antlr.TerminalNode
THEN_() antlr.TerminalNode
TO_() antlr.TerminalNode
TRANSACTION_() antlr.TerminalNode
TRIGGER_() antlr.TerminalNode
UNION_() antlr.TerminalNode
UNIQUE_() antlr.TerminalNode
UPDATE_() antlr.TerminalNode
USING_() antlr.TerminalNode
VACUUM_() antlr.TerminalNode
VALUES_() antlr.TerminalNode
VIEW_() antlr.TerminalNode
VIRTUAL_() antlr.TerminalNode
WHEN_() antlr.TerminalNode
WHERE_() antlr.TerminalNode
WITH_() antlr.TerminalNode
WITHOUT_() antlr.TerminalNode
FIRST_VALUE_() antlr.TerminalNode
OVER_() antlr.TerminalNode
PARTITION_() antlr.TerminalNode
RANGE_() antlr.TerminalNode
PRECEDING_() antlr.TerminalNode
UNBOUNDED_() antlr.TerminalNode
CURRENT_() antlr.TerminalNode
FOLLOWING_() antlr.TerminalNode
CUME_DIST_() antlr.TerminalNode
DENSE_RANK_() antlr.TerminalNode
LAG_() antlr.TerminalNode
LAST_VALUE_() antlr.TerminalNode
LEAD_() antlr.TerminalNode
NTH_VALUE_() antlr.TerminalNode
NTILE_() antlr.TerminalNode
PERCENT_RANK_() antlr.TerminalNode
RANK_() antlr.TerminalNode
ROW_NUMBER_() antlr.TerminalNode
GENERATED_() antlr.TerminalNode
ALWAYS_() antlr.TerminalNode
STORED_() antlr.TerminalNode
TRUE_() antlr.TerminalNode
FALSE_() antlr.TerminalNode
WINDOW_() antlr.TerminalNode
NULLS_() antlr.TerminalNode
FIRST_() antlr.TerminalNode
LAST_() antlr.TerminalNode
FILTER_() antlr.TerminalNode
GROUPS_() antlr.TerminalNode
EXCLUDE_() antlr.TerminalNode
// IsKeywordContext differentiates from other interfaces.
IsKeywordContext()
}
type KeywordContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyKeywordContext() *KeywordContext {
var p = new(KeywordContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_keyword
return p
}
func InitEmptyKeywordContext(p *KeywordContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_keyword
}
func (*KeywordContext) IsKeywordContext() {}
func NewKeywordContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *KeywordContext {
var p = new(KeywordContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_keyword
return p
}
func (s *KeywordContext) GetParser() antlr.Parser { return s.parser }
func (s *KeywordContext) ABORT_() antlr.TerminalNode {
return s.GetToken(ParserABORT_, 0)
}
func (s *KeywordContext) ACTION_() antlr.TerminalNode {
return s.GetToken(ParserACTION_, 0)
}
func (s *KeywordContext) ADD_() antlr.TerminalNode {
return s.GetToken(ParserADD_, 0)
}
func (s *KeywordContext) AFTER_() antlr.TerminalNode {
return s.GetToken(ParserAFTER_, 0)
}
func (s *KeywordContext) ALL_() antlr.TerminalNode {
return s.GetToken(ParserALL_, 0)
}
func (s *KeywordContext) ALTER_() antlr.TerminalNode {
return s.GetToken(ParserALTER_, 0)
}
func (s *KeywordContext) ANALYZE_() antlr.TerminalNode {
return s.GetToken(ParserANALYZE_, 0)
}
func (s *KeywordContext) AND_() antlr.TerminalNode {
return s.GetToken(ParserAND_, 0)
}
func (s *KeywordContext) AS_() antlr.TerminalNode {
return s.GetToken(ParserAS_, 0)
}
func (s *KeywordContext) ASC_() antlr.TerminalNode {
return s.GetToken(ParserASC_, 0)
}
func (s *KeywordContext) ATTACH_() antlr.TerminalNode {
return s.GetToken(ParserATTACH_, 0)
}
func (s *KeywordContext) AUTOINCREMENT_() antlr.TerminalNode {
return s.GetToken(ParserAUTOINCREMENT_, 0)
}
func (s *KeywordContext) BEFORE_() antlr.TerminalNode {
return s.GetToken(ParserBEFORE_, 0)
}
func (s *KeywordContext) BEGIN_() antlr.TerminalNode {
return s.GetToken(ParserBEGIN_, 0)
}
func (s *KeywordContext) BETWEEN_() antlr.TerminalNode {
return s.GetToken(ParserBETWEEN_, 0)
}
func (s *KeywordContext) BY_() antlr.TerminalNode {
return s.GetToken(ParserBY_, 0)
}
func (s *KeywordContext) CASCADE_() antlr.TerminalNode {
return s.GetToken(ParserCASCADE_, 0)
}
func (s *KeywordContext) CASE_() antlr.TerminalNode {
return s.GetToken(ParserCASE_, 0)
}
func (s *KeywordContext) CAST_() antlr.TerminalNode {
return s.GetToken(ParserCAST_, 0)
}
func (s *KeywordContext) CHECK_() antlr.TerminalNode {
return s.GetToken(ParserCHECK_, 0)
}
func (s *KeywordContext) COLLATE_() antlr.TerminalNode {
return s.GetToken(ParserCOLLATE_, 0)
}
func (s *KeywordContext) COLUMN_() antlr.TerminalNode {
return s.GetToken(ParserCOLUMN_, 0)
}
func (s *KeywordContext) COMMIT_() antlr.TerminalNode {
return s.GetToken(ParserCOMMIT_, 0)
}
func (s *KeywordContext) CONFLICT_() antlr.TerminalNode {
return s.GetToken(ParserCONFLICT_, 0)
}
func (s *KeywordContext) CONSTRAINT_() antlr.TerminalNode {
return s.GetToken(ParserCONSTRAINT_, 0)
}
func (s *KeywordContext) CREATE_() antlr.TerminalNode {
return s.GetToken(ParserCREATE_, 0)
}
func (s *KeywordContext) CROSS_() antlr.TerminalNode {
return s.GetToken(ParserCROSS_, 0)
}
func (s *KeywordContext) CURRENT_DATE_() antlr.TerminalNode {
return s.GetToken(ParserCURRENT_DATE_, 0)
}
func (s *KeywordContext) CURRENT_TIME_() antlr.TerminalNode {
return s.GetToken(ParserCURRENT_TIME_, 0)
}
func (s *KeywordContext) CURRENT_TIMESTAMP_() antlr.TerminalNode {
return s.GetToken(ParserCURRENT_TIMESTAMP_, 0)
}
func (s *KeywordContext) DATABASE_() antlr.TerminalNode {
return s.GetToken(ParserDATABASE_, 0)
}
func (s *KeywordContext) DEFAULT_() antlr.TerminalNode {
return s.GetToken(ParserDEFAULT_, 0)
}
func (s *KeywordContext) DEFERRABLE_() antlr.TerminalNode {
return s.GetToken(ParserDEFERRABLE_, 0)
}
func (s *KeywordContext) DEFERRED_() antlr.TerminalNode {
return s.GetToken(ParserDEFERRED_, 0)
}
func (s *KeywordContext) DELETE_() antlr.TerminalNode {
return s.GetToken(ParserDELETE_, 0)
}
func (s *KeywordContext) DESC_() antlr.TerminalNode {
return s.GetToken(ParserDESC_, 0)
}
func (s *KeywordContext) DETACH_() antlr.TerminalNode {
return s.GetToken(ParserDETACH_, 0)
}
func (s *KeywordContext) DISTINCT_() antlr.TerminalNode {
return s.GetToken(ParserDISTINCT_, 0)
}
func (s *KeywordContext) DROP_() antlr.TerminalNode {
return s.GetToken(ParserDROP_, 0)
}
func (s *KeywordContext) EACH_() antlr.TerminalNode {
return s.GetToken(ParserEACH_, 0)
}
func (s *KeywordContext) ELSE_() antlr.TerminalNode {
return s.GetToken(ParserELSE_, 0)
}
func (s *KeywordContext) END_() antlr.TerminalNode {
return s.GetToken(ParserEND_, 0)
}
func (s *KeywordContext) ESCAPE_() antlr.TerminalNode {
return s.GetToken(ParserESCAPE_, 0)
}
func (s *KeywordContext) EXCEPT_() antlr.TerminalNode {
return s.GetToken(ParserEXCEPT_, 0)
}
func (s *KeywordContext) EXCLUSIVE_() antlr.TerminalNode {
return s.GetToken(ParserEXCLUSIVE_, 0)
}
func (s *KeywordContext) EXISTS_() antlr.TerminalNode {
return s.GetToken(ParserEXISTS_, 0)
}
func (s *KeywordContext) EXPLAIN_() antlr.TerminalNode {
return s.GetToken(ParserEXPLAIN_, 0)
}
func (s *KeywordContext) FAIL_() antlr.TerminalNode {
return s.GetToken(ParserFAIL_, 0)
}
func (s *KeywordContext) FOR_() antlr.TerminalNode {
return s.GetToken(ParserFOR_, 0)
}
func (s *KeywordContext) FOREIGN_() antlr.TerminalNode {
return s.GetToken(ParserFOREIGN_, 0)
}
func (s *KeywordContext) FROM_() antlr.TerminalNode {
return s.GetToken(ParserFROM_, 0)
}
func (s *KeywordContext) FULL_() antlr.TerminalNode {
return s.GetToken(ParserFULL_, 0)
}
func (s *KeywordContext) GLOB_() antlr.TerminalNode {
return s.GetToken(ParserGLOB_, 0)
}
func (s *KeywordContext) GROUP_() antlr.TerminalNode {
return s.GetToken(ParserGROUP_, 0)
}
func (s *KeywordContext) HAVING_() antlr.TerminalNode {
return s.GetToken(ParserHAVING_, 0)
}
func (s *KeywordContext) IF_() antlr.TerminalNode {
return s.GetToken(ParserIF_, 0)
}
func (s *KeywordContext) IGNORE_() antlr.TerminalNode {
return s.GetToken(ParserIGNORE_, 0)
}
func (s *KeywordContext) IMMEDIATE_() antlr.TerminalNode {
return s.GetToken(ParserIMMEDIATE_, 0)
}
func (s *KeywordContext) IN_() antlr.TerminalNode {
return s.GetToken(ParserIN_, 0)
}
func (s *KeywordContext) INDEX_() antlr.TerminalNode {
return s.GetToken(ParserINDEX_, 0)
}
func (s *KeywordContext) INDEXED_() antlr.TerminalNode {
return s.GetToken(ParserINDEXED_, 0)
}
func (s *KeywordContext) INITIALLY_() antlr.TerminalNode {
return s.GetToken(ParserINITIALLY_, 0)
}
func (s *KeywordContext) INNER_() antlr.TerminalNode {
return s.GetToken(ParserINNER_, 0)
}
func (s *KeywordContext) INSERT_() antlr.TerminalNode {
return s.GetToken(ParserINSERT_, 0)
}
func (s *KeywordContext) INSTEAD_() antlr.TerminalNode {
return s.GetToken(ParserINSTEAD_, 0)
}
func (s *KeywordContext) INTERSECT_() antlr.TerminalNode {
return s.GetToken(ParserINTERSECT_, 0)
}
func (s *KeywordContext) INTO_() antlr.TerminalNode {
return s.GetToken(ParserINTO_, 0)
}
func (s *KeywordContext) IS_() antlr.TerminalNode {
return s.GetToken(ParserIS_, 0)
}
func (s *KeywordContext) ISNULL_() antlr.TerminalNode {
return s.GetToken(ParserISNULL_, 0)
}
func (s *KeywordContext) JOIN_() antlr.TerminalNode {
return s.GetToken(ParserJOIN_, 0)
}
func (s *KeywordContext) KEY_() antlr.TerminalNode {
return s.GetToken(ParserKEY_, 0)
}
func (s *KeywordContext) LEFT_() antlr.TerminalNode {
return s.GetToken(ParserLEFT_, 0)
}
func (s *KeywordContext) LIKE_() antlr.TerminalNode {
return s.GetToken(ParserLIKE_, 0)
}
func (s *KeywordContext) LIMIT_() antlr.TerminalNode {
return s.GetToken(ParserLIMIT_, 0)
}
func (s *KeywordContext) MATCH_() antlr.TerminalNode {
return s.GetToken(ParserMATCH_, 0)
}
func (s *KeywordContext) NATURAL_() antlr.TerminalNode {
return s.GetToken(ParserNATURAL_, 0)
}
func (s *KeywordContext) NO_() antlr.TerminalNode {
return s.GetToken(ParserNO_, 0)
}
func (s *KeywordContext) NOT_() antlr.TerminalNode {
return s.GetToken(ParserNOT_, 0)
}
func (s *KeywordContext) NOTNULL_() antlr.TerminalNode {
return s.GetToken(ParserNOTNULL_, 0)
}
func (s *KeywordContext) NULL_() antlr.TerminalNode {
return s.GetToken(ParserNULL_, 0)
}
func (s *KeywordContext) OF_() antlr.TerminalNode {
return s.GetToken(ParserOF_, 0)
}
func (s *KeywordContext) OFFSET_() antlr.TerminalNode {
return s.GetToken(ParserOFFSET_, 0)
}
func (s *KeywordContext) ON_() antlr.TerminalNode {
return s.GetToken(ParserON_, 0)
}
func (s *KeywordContext) OR_() antlr.TerminalNode {
return s.GetToken(ParserOR_, 0)
}
func (s *KeywordContext) ORDER_() antlr.TerminalNode {
return s.GetToken(ParserORDER_, 0)
}
func (s *KeywordContext) OUTER_() antlr.TerminalNode {
return s.GetToken(ParserOUTER_, 0)
}
func (s *KeywordContext) PLAN_() antlr.TerminalNode {
return s.GetToken(ParserPLAN_, 0)
}
func (s *KeywordContext) PRAGMA_() antlr.TerminalNode {
return s.GetToken(ParserPRAGMA_, 0)
}
func (s *KeywordContext) PRIMARY_() antlr.TerminalNode {
return s.GetToken(ParserPRIMARY_, 0)
}
func (s *KeywordContext) QUERY_() antlr.TerminalNode {
return s.GetToken(ParserQUERY_, 0)
}
func (s *KeywordContext) RAISE_() antlr.TerminalNode {
return s.GetToken(ParserRAISE_, 0)
}
func (s *KeywordContext) RECURSIVE_() antlr.TerminalNode {
return s.GetToken(ParserRECURSIVE_, 0)
}
func (s *KeywordContext) REFERENCES_() antlr.TerminalNode {
return s.GetToken(ParserREFERENCES_, 0)
}
func (s *KeywordContext) REGEXP_() antlr.TerminalNode {
return s.GetToken(ParserREGEXP_, 0)
}
func (s *KeywordContext) REINDEX_() antlr.TerminalNode {
return s.GetToken(ParserREINDEX_, 0)
}
func (s *KeywordContext) RELEASE_() antlr.TerminalNode {
return s.GetToken(ParserRELEASE_, 0)
}
func (s *KeywordContext) RENAME_() antlr.TerminalNode {
return s.GetToken(ParserRENAME_, 0)
}
func (s *KeywordContext) REPLACE_() antlr.TerminalNode {
return s.GetToken(ParserREPLACE_, 0)
}
func (s *KeywordContext) RESTRICT_() antlr.TerminalNode {
return s.GetToken(ParserRESTRICT_, 0)
}
func (s *KeywordContext) RIGHT_() antlr.TerminalNode {
return s.GetToken(ParserRIGHT_, 0)
}
func (s *KeywordContext) ROLLBACK_() antlr.TerminalNode {
return s.GetToken(ParserROLLBACK_, 0)
}
func (s *KeywordContext) ROW_() antlr.TerminalNode {
return s.GetToken(ParserROW_, 0)
}
func (s *KeywordContext) ROWS_() antlr.TerminalNode {
return s.GetToken(ParserROWS_, 0)
}
func (s *KeywordContext) SAVEPOINT_() antlr.TerminalNode {
return s.GetToken(ParserSAVEPOINT_, 0)
}
func (s *KeywordContext) SELECT_() antlr.TerminalNode {
return s.GetToken(ParserSELECT_, 0)
}
func (s *KeywordContext) SET_() antlr.TerminalNode {
return s.GetToken(ParserSET_, 0)
}
func (s *KeywordContext) TABLE_() antlr.TerminalNode {
return s.GetToken(ParserTABLE_, 0)
}
func (s *KeywordContext) TEMP_() antlr.TerminalNode {
return s.GetToken(ParserTEMP_, 0)
}
func (s *KeywordContext) TEMPORARY_() antlr.TerminalNode {
return s.GetToken(ParserTEMPORARY_, 0)
}
func (s *KeywordContext) THEN_() antlr.TerminalNode {
return s.GetToken(ParserTHEN_, 0)
}
func (s *KeywordContext) TO_() antlr.TerminalNode {
return s.GetToken(ParserTO_, 0)
}
func (s *KeywordContext) TRANSACTION_() antlr.TerminalNode {
return s.GetToken(ParserTRANSACTION_, 0)
}
func (s *KeywordContext) TRIGGER_() antlr.TerminalNode {
return s.GetToken(ParserTRIGGER_, 0)
}
func (s *KeywordContext) UNION_() antlr.TerminalNode {
return s.GetToken(ParserUNION_, 0)
}
func (s *KeywordContext) UNIQUE_() antlr.TerminalNode {
return s.GetToken(ParserUNIQUE_, 0)
}
func (s *KeywordContext) UPDATE_() antlr.TerminalNode {
return s.GetToken(ParserUPDATE_, 0)
}
func (s *KeywordContext) USING_() antlr.TerminalNode {
return s.GetToken(ParserUSING_, 0)
}
func (s *KeywordContext) VACUUM_() antlr.TerminalNode {
return s.GetToken(ParserVACUUM_, 0)
}
func (s *KeywordContext) VALUES_() antlr.TerminalNode {
return s.GetToken(ParserVALUES_, 0)
}
func (s *KeywordContext) VIEW_() antlr.TerminalNode {
return s.GetToken(ParserVIEW_, 0)
}
func (s *KeywordContext) VIRTUAL_() antlr.TerminalNode {
return s.GetToken(ParserVIRTUAL_, 0)
}
func (s *KeywordContext) WHEN_() antlr.TerminalNode {
return s.GetToken(ParserWHEN_, 0)
}
func (s *KeywordContext) WHERE_() antlr.TerminalNode {
return s.GetToken(ParserWHERE_, 0)
}
func (s *KeywordContext) WITH_() antlr.TerminalNode {
return s.GetToken(ParserWITH_, 0)
}
func (s *KeywordContext) WITHOUT_() antlr.TerminalNode {
return s.GetToken(ParserWITHOUT_, 0)
}
func (s *KeywordContext) FIRST_VALUE_() antlr.TerminalNode {
return s.GetToken(ParserFIRST_VALUE_, 0)
}
func (s *KeywordContext) OVER_() antlr.TerminalNode {
return s.GetToken(ParserOVER_, 0)
}
func (s *KeywordContext) PARTITION_() antlr.TerminalNode {
return s.GetToken(ParserPARTITION_, 0)
}
func (s *KeywordContext) RANGE_() antlr.TerminalNode {
return s.GetToken(ParserRANGE_, 0)
}
func (s *KeywordContext) PRECEDING_() antlr.TerminalNode {
return s.GetToken(ParserPRECEDING_, 0)
}
func (s *KeywordContext) UNBOUNDED_() antlr.TerminalNode {
return s.GetToken(ParserUNBOUNDED_, 0)
}
func (s *KeywordContext) CURRENT_() antlr.TerminalNode {
return s.GetToken(ParserCURRENT_, 0)
}
func (s *KeywordContext) FOLLOWING_() antlr.TerminalNode {
return s.GetToken(ParserFOLLOWING_, 0)
}
func (s *KeywordContext) CUME_DIST_() antlr.TerminalNode {
return s.GetToken(ParserCUME_DIST_, 0)
}
func (s *KeywordContext) DENSE_RANK_() antlr.TerminalNode {
return s.GetToken(ParserDENSE_RANK_, 0)
}
func (s *KeywordContext) LAG_() antlr.TerminalNode {
return s.GetToken(ParserLAG_, 0)
}
func (s *KeywordContext) LAST_VALUE_() antlr.TerminalNode {
return s.GetToken(ParserLAST_VALUE_, 0)
}
func (s *KeywordContext) LEAD_() antlr.TerminalNode {
return s.GetToken(ParserLEAD_, 0)
}
func (s *KeywordContext) NTH_VALUE_() antlr.TerminalNode {
return s.GetToken(ParserNTH_VALUE_, 0)
}
func (s *KeywordContext) NTILE_() antlr.TerminalNode {
return s.GetToken(ParserNTILE_, 0)
}
func (s *KeywordContext) PERCENT_RANK_() antlr.TerminalNode {
return s.GetToken(ParserPERCENT_RANK_, 0)
}
func (s *KeywordContext) RANK_() antlr.TerminalNode {
return s.GetToken(ParserRANK_, 0)
}
func (s *KeywordContext) ROW_NUMBER_() antlr.TerminalNode {
return s.GetToken(ParserROW_NUMBER_, 0)
}
func (s *KeywordContext) GENERATED_() antlr.TerminalNode {
return s.GetToken(ParserGENERATED_, 0)
}
func (s *KeywordContext) ALWAYS_() antlr.TerminalNode {
return s.GetToken(ParserALWAYS_, 0)
}
func (s *KeywordContext) STORED_() antlr.TerminalNode {
return s.GetToken(ParserSTORED_, 0)
}
func (s *KeywordContext) TRUE_() antlr.TerminalNode {
return s.GetToken(ParserTRUE_, 0)
}
func (s *KeywordContext) FALSE_() antlr.TerminalNode {
return s.GetToken(ParserFALSE_, 0)
}
func (s *KeywordContext) WINDOW_() antlr.TerminalNode {
return s.GetToken(ParserWINDOW_, 0)
}
func (s *KeywordContext) NULLS_() antlr.TerminalNode {
return s.GetToken(ParserNULLS_, 0)
}
func (s *KeywordContext) FIRST_() antlr.TerminalNode {
return s.GetToken(ParserFIRST_, 0)
}
func (s *KeywordContext) LAST_() antlr.TerminalNode {
return s.GetToken(ParserLAST_, 0)
}
func (s *KeywordContext) FILTER_() antlr.TerminalNode {
return s.GetToken(ParserFILTER_, 0)
}
func (s *KeywordContext) GROUPS_() antlr.TerminalNode {
return s.GetToken(ParserGROUPS_, 0)
}
func (s *KeywordContext) EXCLUDE_() antlr.TerminalNode {
return s.GetToken(ParserEXCLUDE_, 0)
}
func (s *KeywordContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *KeywordContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *KeywordContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterKeyword(s)
}
}
func (s *KeywordContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitKeyword(s)
}
}
func (s *KeywordContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitKeyword(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Keyword() (localctx IKeywordContext) {
localctx = NewKeywordContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 176, ParserRULE_keyword)
var _la int
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2025)
_la = p.GetTokenStream().LA(1)
if !(((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&-33554432) != 0) || ((int64((_la-64)) & ^0x3f) == 0 && ((int64(1)<<(_la-64))&-1152921504606846977) != 0) || ((int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&9007199254740991) != 0)) {
p.GetErrorHandler().RecoverInline(p)
} else {
p.GetErrorHandler().ReportMatch(p)
p.Consume()
}
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// INameContext is an interface to support dynamic dispatch.
type INameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsNameContext differentiates from other interfaces.
IsNameContext()
}
type NameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyNameContext() *NameContext {
var p = new(NameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_name
return p
}
func InitEmptyNameContext(p *NameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_name
}
func (*NameContext) IsNameContext() {}
func NewNameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *NameContext {
var p = new(NameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_name
return p
}
func (s *NameContext) GetParser() antlr.Parser { return s.parser }
func (s *NameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *NameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *NameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *NameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterName(s)
}
}
func (s *NameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitName(s)
}
}
func (s *NameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitName(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Name() (localctx INameContext) {
localctx = NewNameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 178, ParserRULE_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2027)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IFunction_nameContext is an interface to support dynamic dispatch.
type IFunction_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsFunction_nameContext differentiates from other interfaces.
IsFunction_nameContext()
}
type Function_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyFunction_nameContext() *Function_nameContext {
var p = new(Function_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_function_name
return p
}
func InitEmptyFunction_nameContext(p *Function_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_function_name
}
func (*Function_nameContext) IsFunction_nameContext() {}
func NewFunction_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Function_nameContext {
var p = new(Function_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_function_name
return p
}
func (s *Function_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Function_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Function_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Function_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Function_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterFunction_name(s)
}
}
func (s *Function_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitFunction_name(s)
}
}
func (s *Function_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitFunction_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Function_name() (localctx IFunction_nameContext) {
localctx = NewFunction_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 180, ParserRULE_function_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2029)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ISchema_nameContext is an interface to support dynamic dispatch.
type ISchema_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsSchema_nameContext differentiates from other interfaces.
IsSchema_nameContext()
}
type Schema_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptySchema_nameContext() *Schema_nameContext {
var p = new(Schema_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_schema_name
return p
}
func InitEmptySchema_nameContext(p *Schema_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_schema_name
}
func (*Schema_nameContext) IsSchema_nameContext() {}
func NewSchema_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Schema_nameContext {
var p = new(Schema_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_schema_name
return p
}
func (s *Schema_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Schema_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Schema_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Schema_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Schema_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterSchema_name(s)
}
}
func (s *Schema_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitSchema_name(s)
}
}
func (s *Schema_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitSchema_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Schema_name() (localctx ISchema_nameContext) {
localctx = NewSchema_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 182, ParserRULE_schema_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2031)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ITable_nameContext is an interface to support dynamic dispatch.
type ITable_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsTable_nameContext differentiates from other interfaces.
IsTable_nameContext()
}
type Table_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyTable_nameContext() *Table_nameContext {
var p = new(Table_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_name
return p
}
func InitEmptyTable_nameContext(p *Table_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_name
}
func (*Table_nameContext) IsTable_nameContext() {}
func NewTable_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_nameContext {
var p = new(Table_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_table_name
return p
}
func (s *Table_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Table_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Table_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Table_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Table_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterTable_name(s)
}
}
func (s *Table_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitTable_name(s)
}
}
func (s *Table_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitTable_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Table_name() (localctx ITable_nameContext) {
localctx = NewTable_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 184, ParserRULE_table_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2033)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ITable_or_index_nameContext is an interface to support dynamic dispatch.
type ITable_or_index_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsTable_or_index_nameContext differentiates from other interfaces.
IsTable_or_index_nameContext()
}
type Table_or_index_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyTable_or_index_nameContext() *Table_or_index_nameContext {
var p = new(Table_or_index_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_or_index_name
return p
}
func InitEmptyTable_or_index_nameContext(p *Table_or_index_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_or_index_name
}
func (*Table_or_index_nameContext) IsTable_or_index_nameContext() {}
func NewTable_or_index_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_or_index_nameContext {
var p = new(Table_or_index_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_table_or_index_name
return p
}
func (s *Table_or_index_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Table_or_index_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Table_or_index_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Table_or_index_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Table_or_index_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterTable_or_index_name(s)
}
}
func (s *Table_or_index_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitTable_or_index_name(s)
}
}
func (s *Table_or_index_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitTable_or_index_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Table_or_index_name() (localctx ITable_or_index_nameContext) {
localctx = NewTable_or_index_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 186, ParserRULE_table_or_index_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2035)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IColumn_nameContext is an interface to support dynamic dispatch.
type IColumn_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsColumn_nameContext differentiates from other interfaces.
IsColumn_nameContext()
}
type Column_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyColumn_nameContext() *Column_nameContext {
var p = new(Column_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_column_name
return p
}
func InitEmptyColumn_nameContext(p *Column_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_column_name
}
func (*Column_nameContext) IsColumn_nameContext() {}
func NewColumn_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Column_nameContext {
var p = new(Column_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_column_name
return p
}
func (s *Column_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Column_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Column_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Column_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Column_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterColumn_name(s)
}
}
func (s *Column_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitColumn_name(s)
}
}
func (s *Column_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitColumn_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Column_name() (localctx IColumn_nameContext) {
localctx = NewColumn_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 188, ParserRULE_column_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2037)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ICollation_nameContext is an interface to support dynamic dispatch.
type ICollation_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsCollation_nameContext differentiates from other interfaces.
IsCollation_nameContext()
}
type Collation_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyCollation_nameContext() *Collation_nameContext {
var p = new(Collation_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_collation_name
return p
}
func InitEmptyCollation_nameContext(p *Collation_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_collation_name
}
func (*Collation_nameContext) IsCollation_nameContext() {}
func NewCollation_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Collation_nameContext {
var p = new(Collation_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_collation_name
return p
}
func (s *Collation_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Collation_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Collation_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Collation_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Collation_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterCollation_name(s)
}
}
func (s *Collation_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitCollation_name(s)
}
}
func (s *Collation_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitCollation_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Collation_name() (localctx ICollation_nameContext) {
localctx = NewCollation_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 190, ParserRULE_collation_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2039)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IForeign_tableContext is an interface to support dynamic dispatch.
type IForeign_tableContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsForeign_tableContext differentiates from other interfaces.
IsForeign_tableContext()
}
type Foreign_tableContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyForeign_tableContext() *Foreign_tableContext {
var p = new(Foreign_tableContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_foreign_table
return p
}
func InitEmptyForeign_tableContext(p *Foreign_tableContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_foreign_table
}
func (*Foreign_tableContext) IsForeign_tableContext() {}
func NewForeign_tableContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Foreign_tableContext {
var p = new(Foreign_tableContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_foreign_table
return p
}
func (s *Foreign_tableContext) GetParser() antlr.Parser { return s.parser }
func (s *Foreign_tableContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Foreign_tableContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Foreign_tableContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Foreign_tableContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterForeign_table(s)
}
}
func (s *Foreign_tableContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitForeign_table(s)
}
}
func (s *Foreign_tableContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitForeign_table(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Foreign_table() (localctx IForeign_tableContext) {
localctx = NewForeign_tableContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 192, ParserRULE_foreign_table)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2041)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IIndex_nameContext is an interface to support dynamic dispatch.
type IIndex_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsIndex_nameContext differentiates from other interfaces.
IsIndex_nameContext()
}
type Index_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyIndex_nameContext() *Index_nameContext {
var p = new(Index_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_index_name
return p
}
func InitEmptyIndex_nameContext(p *Index_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_index_name
}
func (*Index_nameContext) IsIndex_nameContext() {}
func NewIndex_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Index_nameContext {
var p = new(Index_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_index_name
return p
}
func (s *Index_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Index_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Index_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Index_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Index_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterIndex_name(s)
}
}
func (s *Index_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitIndex_name(s)
}
}
func (s *Index_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitIndex_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Index_name() (localctx IIndex_nameContext) {
localctx = NewIndex_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 194, ParserRULE_index_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2043)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ITrigger_nameContext is an interface to support dynamic dispatch.
type ITrigger_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsTrigger_nameContext differentiates from other interfaces.
IsTrigger_nameContext()
}
type Trigger_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyTrigger_nameContext() *Trigger_nameContext {
var p = new(Trigger_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_trigger_name
return p
}
func InitEmptyTrigger_nameContext(p *Trigger_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_trigger_name
}
func (*Trigger_nameContext) IsTrigger_nameContext() {}
func NewTrigger_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Trigger_nameContext {
var p = new(Trigger_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_trigger_name
return p
}
func (s *Trigger_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Trigger_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Trigger_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Trigger_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Trigger_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterTrigger_name(s)
}
}
func (s *Trigger_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitTrigger_name(s)
}
}
func (s *Trigger_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitTrigger_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Trigger_name() (localctx ITrigger_nameContext) {
localctx = NewTrigger_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 196, ParserRULE_trigger_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2045)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IView_nameContext is an interface to support dynamic dispatch.
type IView_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsView_nameContext differentiates from other interfaces.
IsView_nameContext()
}
type View_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyView_nameContext() *View_nameContext {
var p = new(View_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_view_name
return p
}
func InitEmptyView_nameContext(p *View_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_view_name
}
func (*View_nameContext) IsView_nameContext() {}
func NewView_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *View_nameContext {
var p = new(View_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_view_name
return p
}
func (s *View_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *View_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *View_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *View_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *View_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterView_name(s)
}
}
func (s *View_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitView_name(s)
}
}
func (s *View_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitView_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) View_name() (localctx IView_nameContext) {
localctx = NewView_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 198, ParserRULE_view_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2047)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IModule_nameContext is an interface to support dynamic dispatch.
type IModule_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsModule_nameContext differentiates from other interfaces.
IsModule_nameContext()
}
type Module_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyModule_nameContext() *Module_nameContext {
var p = new(Module_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_module_name
return p
}
func InitEmptyModule_nameContext(p *Module_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_module_name
}
func (*Module_nameContext) IsModule_nameContext() {}
func NewModule_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Module_nameContext {
var p = new(Module_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_module_name
return p
}
func (s *Module_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Module_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Module_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Module_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Module_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterModule_name(s)
}
}
func (s *Module_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitModule_name(s)
}
}
func (s *Module_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitModule_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Module_name() (localctx IModule_nameContext) {
localctx = NewModule_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 200, ParserRULE_module_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2049)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IPragma_nameContext is an interface to support dynamic dispatch.
type IPragma_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsPragma_nameContext differentiates from other interfaces.
IsPragma_nameContext()
}
type Pragma_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyPragma_nameContext() *Pragma_nameContext {
var p = new(Pragma_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_pragma_name
return p
}
func InitEmptyPragma_nameContext(p *Pragma_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_pragma_name
}
func (*Pragma_nameContext) IsPragma_nameContext() {}
func NewPragma_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Pragma_nameContext {
var p = new(Pragma_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_pragma_name
return p
}
func (s *Pragma_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Pragma_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Pragma_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Pragma_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Pragma_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterPragma_name(s)
}
}
func (s *Pragma_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitPragma_name(s)
}
}
func (s *Pragma_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitPragma_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Pragma_name() (localctx IPragma_nameContext) {
localctx = NewPragma_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 202, ParserRULE_pragma_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2051)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ISavepoint_nameContext is an interface to support dynamic dispatch.
type ISavepoint_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsSavepoint_nameContext differentiates from other interfaces.
IsSavepoint_nameContext()
}
type Savepoint_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptySavepoint_nameContext() *Savepoint_nameContext {
var p = new(Savepoint_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_savepoint_name
return p
}
func InitEmptySavepoint_nameContext(p *Savepoint_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_savepoint_name
}
func (*Savepoint_nameContext) IsSavepoint_nameContext() {}
func NewSavepoint_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Savepoint_nameContext {
var p = new(Savepoint_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_savepoint_name
return p
}
func (s *Savepoint_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Savepoint_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Savepoint_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Savepoint_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Savepoint_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterSavepoint_name(s)
}
}
func (s *Savepoint_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitSavepoint_name(s)
}
}
func (s *Savepoint_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitSavepoint_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Savepoint_name() (localctx ISavepoint_nameContext) {
localctx = NewSavepoint_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 204, ParserRULE_savepoint_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2053)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ITable_aliasContext is an interface to support dynamic dispatch.
type ITable_aliasContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsTable_aliasContext differentiates from other interfaces.
IsTable_aliasContext()
}
type Table_aliasContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyTable_aliasContext() *Table_aliasContext {
var p = new(Table_aliasContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_alias
return p
}
func InitEmptyTable_aliasContext(p *Table_aliasContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_alias
}
func (*Table_aliasContext) IsTable_aliasContext() {}
func NewTable_aliasContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_aliasContext {
var p = new(Table_aliasContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_table_alias
return p
}
func (s *Table_aliasContext) GetParser() antlr.Parser { return s.parser }
func (s *Table_aliasContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Table_aliasContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Table_aliasContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Table_aliasContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterTable_alias(s)
}
}
func (s *Table_aliasContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitTable_alias(s)
}
}
func (s *Table_aliasContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitTable_alias(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Table_alias() (localctx ITable_aliasContext) {
localctx = NewTable_aliasContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 206, ParserRULE_table_alias)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2055)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ITransaction_nameContext is an interface to support dynamic dispatch.
type ITransaction_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsTransaction_nameContext differentiates from other interfaces.
IsTransaction_nameContext()
}
type Transaction_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyTransaction_nameContext() *Transaction_nameContext {
var p = new(Transaction_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_transaction_name
return p
}
func InitEmptyTransaction_nameContext(p *Transaction_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_transaction_name
}
func (*Transaction_nameContext) IsTransaction_nameContext() {}
func NewTransaction_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Transaction_nameContext {
var p = new(Transaction_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_transaction_name
return p
}
func (s *Transaction_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Transaction_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Transaction_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Transaction_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Transaction_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterTransaction_name(s)
}
}
func (s *Transaction_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitTransaction_name(s)
}
}
func (s *Transaction_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitTransaction_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Transaction_name() (localctx ITransaction_nameContext) {
localctx = NewTransaction_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 208, ParserRULE_transaction_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2057)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IWindow_nameContext is an interface to support dynamic dispatch.
type IWindow_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsWindow_nameContext differentiates from other interfaces.
IsWindow_nameContext()
}
type Window_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyWindow_nameContext() *Window_nameContext {
var p = new(Window_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_window_name
return p
}
func InitEmptyWindow_nameContext(p *Window_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_window_name
}
func (*Window_nameContext) IsWindow_nameContext() {}
func NewWindow_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Window_nameContext {
var p = new(Window_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_window_name
return p
}
func (s *Window_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Window_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Window_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Window_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Window_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterWindow_name(s)
}
}
func (s *Window_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitWindow_name(s)
}
}
func (s *Window_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitWindow_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Window_name() (localctx IWindow_nameContext) {
localctx = NewWindow_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 210, ParserRULE_window_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2059)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IAliasContext is an interface to support dynamic dispatch.
type IAliasContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsAliasContext differentiates from other interfaces.
IsAliasContext()
}
type AliasContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyAliasContext() *AliasContext {
var p = new(AliasContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_alias
return p
}
func InitEmptyAliasContext(p *AliasContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_alias
}
func (*AliasContext) IsAliasContext() {}
func NewAliasContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *AliasContext {
var p = new(AliasContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_alias
return p
}
func (s *AliasContext) GetParser() antlr.Parser { return s.parser }
func (s *AliasContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *AliasContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *AliasContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *AliasContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterAlias(s)
}
}
func (s *AliasContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitAlias(s)
}
}
func (s *AliasContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitAlias(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Alias() (localctx IAliasContext) {
localctx = NewAliasContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 212, ParserRULE_alias)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2061)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IFilenameContext is an interface to support dynamic dispatch.
type IFilenameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsFilenameContext differentiates from other interfaces.
IsFilenameContext()
}
type FilenameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyFilenameContext() *FilenameContext {
var p = new(FilenameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_filename
return p
}
func InitEmptyFilenameContext(p *FilenameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_filename
}
func (*FilenameContext) IsFilenameContext() {}
func NewFilenameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *FilenameContext {
var p = new(FilenameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_filename
return p
}
func (s *FilenameContext) GetParser() antlr.Parser { return s.parser }
func (s *FilenameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *FilenameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *FilenameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *FilenameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterFilename(s)
}
}
func (s *FilenameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitFilename(s)
}
}
func (s *FilenameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitFilename(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Filename() (localctx IFilenameContext) {
localctx = NewFilenameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 214, ParserRULE_filename)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2063)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IBase_window_nameContext is an interface to support dynamic dispatch.
type IBase_window_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsBase_window_nameContext differentiates from other interfaces.
IsBase_window_nameContext()
}
type Base_window_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyBase_window_nameContext() *Base_window_nameContext {
var p = new(Base_window_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_base_window_name
return p
}
func InitEmptyBase_window_nameContext(p *Base_window_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_base_window_name
}
func (*Base_window_nameContext) IsBase_window_nameContext() {}
func NewBase_window_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Base_window_nameContext {
var p = new(Base_window_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_base_window_name
return p
}
func (s *Base_window_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Base_window_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Base_window_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Base_window_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Base_window_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterBase_window_name(s)
}
}
func (s *Base_window_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitBase_window_name(s)
}
}
func (s *Base_window_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitBase_window_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Base_window_name() (localctx IBase_window_nameContext) {
localctx = NewBase_window_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 216, ParserRULE_base_window_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2065)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ISimple_funcContext is an interface to support dynamic dispatch.
type ISimple_funcContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsSimple_funcContext differentiates from other interfaces.
IsSimple_funcContext()
}
type Simple_funcContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptySimple_funcContext() *Simple_funcContext {
var p = new(Simple_funcContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_simple_func
return p
}
func InitEmptySimple_funcContext(p *Simple_funcContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_simple_func
}
func (*Simple_funcContext) IsSimple_funcContext() {}
func NewSimple_funcContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Simple_funcContext {
var p = new(Simple_funcContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_simple_func
return p
}
func (s *Simple_funcContext) GetParser() antlr.Parser { return s.parser }
func (s *Simple_funcContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Simple_funcContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Simple_funcContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Simple_funcContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterSimple_func(s)
}
}
func (s *Simple_funcContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitSimple_func(s)
}
}
func (s *Simple_funcContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitSimple_func(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Simple_func() (localctx ISimple_funcContext) {
localctx = NewSimple_funcContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 218, ParserRULE_simple_func)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2067)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IAggregate_funcContext is an interface to support dynamic dispatch.
type IAggregate_funcContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsAggregate_funcContext differentiates from other interfaces.
IsAggregate_funcContext()
}
type Aggregate_funcContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyAggregate_funcContext() *Aggregate_funcContext {
var p = new(Aggregate_funcContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_aggregate_func
return p
}
func InitEmptyAggregate_funcContext(p *Aggregate_funcContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_aggregate_func
}
func (*Aggregate_funcContext) IsAggregate_funcContext() {}
func NewAggregate_funcContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Aggregate_funcContext {
var p = new(Aggregate_funcContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_aggregate_func
return p
}
func (s *Aggregate_funcContext) GetParser() antlr.Parser { return s.parser }
func (s *Aggregate_funcContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Aggregate_funcContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Aggregate_funcContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Aggregate_funcContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterAggregate_func(s)
}
}
func (s *Aggregate_funcContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitAggregate_func(s)
}
}
func (s *Aggregate_funcContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitAggregate_func(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Aggregate_func() (localctx IAggregate_funcContext) {
localctx = NewAggregate_funcContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 220, ParserRULE_aggregate_func)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2069)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// ITable_function_nameContext is an interface to support dynamic dispatch.
type ITable_function_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
Any_name() IAny_nameContext
// IsTable_function_nameContext differentiates from other interfaces.
IsTable_function_nameContext()
}
type Table_function_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyTable_function_nameContext() *Table_function_nameContext {
var p = new(Table_function_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_function_name
return p
}
func InitEmptyTable_function_nameContext(p *Table_function_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_table_function_name
}
func (*Table_function_nameContext) IsTable_function_nameContext() {}
func NewTable_function_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_function_nameContext {
var p = new(Table_function_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_table_function_name
return p
}
func (s *Table_function_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Table_function_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Table_function_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Table_function_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Table_function_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterTable_function_name(s)
}
}
func (s *Table_function_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitTable_function_name(s)
}
}
func (s *Table_function_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitTable_function_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Table_function_name() (localctx ITable_function_nameContext) {
localctx = NewTable_function_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 222, ParserRULE_table_function_name)
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2071)
p.Any_name()
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
// IAny_nameContext is an interface to support dynamic dispatch.
type IAny_nameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// Getter signatures
IDENTIFIER() antlr.TerminalNode
Keyword() IKeywordContext
STRING_LITERAL() antlr.TerminalNode
OPEN_PAR() antlr.TerminalNode
Any_name() IAny_nameContext
CLOSE_PAR() antlr.TerminalNode
// IsAny_nameContext differentiates from other interfaces.
IsAny_nameContext()
}
type Any_nameContext struct {
antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyAny_nameContext() *Any_nameContext {
var p = new(Any_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_any_name
return p
}
func InitEmptyAny_nameContext(p *Any_nameContext) {
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
p.RuleIndex = ParserRULE_any_name
}
func (*Any_nameContext) IsAny_nameContext() {}
func NewAny_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Any_nameContext {
var p = new(Any_nameContext)
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
p.parser = parser
p.RuleIndex = ParserRULE_any_name
return p
}
func (s *Any_nameContext) GetParser() antlr.Parser { return s.parser }
func (s *Any_nameContext) IDENTIFIER() antlr.TerminalNode {
return s.GetToken(ParserIDENTIFIER, 0)
}
func (s *Any_nameContext) Keyword() IKeywordContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IKeywordContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IKeywordContext)
}
func (s *Any_nameContext) STRING_LITERAL() antlr.TerminalNode {
return s.GetToken(ParserSTRING_LITERAL, 0)
}
func (s *Any_nameContext) OPEN_PAR() antlr.TerminalNode {
return s.GetToken(ParserOPEN_PAR, 0)
}
func (s *Any_nameContext) Any_name() IAny_nameContext {
var t antlr.RuleContext
for _, ctx := range s.GetChildren() {
if _, ok := ctx.(IAny_nameContext); ok {
t = ctx.(antlr.RuleContext)
break
}
}
if t == nil {
return nil
}
return t.(IAny_nameContext)
}
func (s *Any_nameContext) CLOSE_PAR() antlr.TerminalNode {
return s.GetToken(ParserCLOSE_PAR, 0)
}
func (s *Any_nameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *Any_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *Any_nameContext) EnterRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.EnterAny_name(s)
}
}
func (s *Any_nameContext) ExitRule(listener antlr.ParseTreeListener) {
if listenerT, ok := listener.(ParserListener); ok {
listenerT.ExitAny_name(s)
}
}
func (s *Any_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ParserVisitor:
return t.VisitAny_name(s)
default:
return t.VisitChildren(s)
}
}
func (p *Parser) Any_name() (localctx IAny_nameContext) {
localctx = NewAny_nameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 224, ParserRULE_any_name)
p.SetState(2080)
p.GetErrorHandler().Sync(p)
if p.HasError() {
goto errorExit
}
switch p.GetTokenStream().LA(1) {
case ParserIDENTIFIER:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(2073)
p.Match(ParserIDENTIFIER)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserABORT_, ParserACTION_, ParserADD_, ParserAFTER_, ParserALL_, ParserALTER_, ParserANALYZE_, ParserAND_, ParserAS_, ParserASC_, ParserATTACH_, ParserAUTOINCREMENT_, ParserBEFORE_, ParserBEGIN_, ParserBETWEEN_, ParserBY_, ParserCASCADE_, ParserCASE_, ParserCAST_, ParserCHECK_, ParserCOLLATE_, ParserCOLUMN_, ParserCOMMIT_, ParserCONFLICT_, ParserCONSTRAINT_, ParserCREATE_, ParserCROSS_, ParserCURRENT_DATE_, ParserCURRENT_TIME_, ParserCURRENT_TIMESTAMP_, ParserDATABASE_, ParserDEFAULT_, ParserDEFERRABLE_, ParserDEFERRED_, ParserDELETE_, ParserDESC_, ParserDETACH_, ParserDISTINCT_, ParserDROP_, ParserEACH_, ParserELSE_, ParserEND_, ParserESCAPE_, ParserEXCEPT_, ParserEXCLUSIVE_, ParserEXISTS_, ParserEXPLAIN_, ParserFAIL_, ParserFOR_, ParserFOREIGN_, ParserFROM_, ParserFULL_, ParserGLOB_, ParserGROUP_, ParserHAVING_, ParserIF_, ParserIGNORE_, ParserIMMEDIATE_, ParserIN_, ParserINDEX_, ParserINDEXED_, ParserINITIALLY_, ParserINNER_, ParserINSERT_, ParserINSTEAD_, ParserINTERSECT_, ParserINTO_, ParserIS_, ParserISNULL_, ParserJOIN_, ParserKEY_, ParserLEFT_, ParserLIKE_, ParserLIMIT_, ParserMATCH_, ParserNATURAL_, ParserNO_, ParserNOT_, ParserNOTNULL_, ParserNULL_, ParserOF_, ParserOFFSET_, ParserON_, ParserOR_, ParserORDER_, ParserOUTER_, ParserPLAN_, ParserPRAGMA_, ParserPRIMARY_, ParserQUERY_, ParserRAISE_, ParserRECURSIVE_, ParserREFERENCES_, ParserREGEXP_, ParserREINDEX_, ParserRELEASE_, ParserRENAME_, ParserREPLACE_, ParserRESTRICT_, ParserRIGHT_, ParserROLLBACK_, ParserROW_, ParserROWS_, ParserSAVEPOINT_, ParserSELECT_, ParserSET_, ParserTABLE_, ParserTEMP_, ParserTEMPORARY_, ParserTHEN_, ParserTO_, ParserTRANSACTION_, ParserTRIGGER_, ParserUNION_, ParserUNIQUE_, ParserUPDATE_, ParserUSING_, ParserVACUUM_, ParserVALUES_, ParserVIEW_, ParserVIRTUAL_, ParserWHEN_, ParserWHERE_, ParserWITH_, ParserWITHOUT_, ParserFIRST_VALUE_, ParserOVER_, ParserPARTITION_, ParserRANGE_, ParserPRECEDING_, ParserUNBOUNDED_, ParserCURRENT_, ParserFOLLOWING_, ParserCUME_DIST_, ParserDENSE_RANK_, ParserLAG_, ParserLAST_VALUE_, ParserLEAD_, ParserNTH_VALUE_, ParserNTILE_, ParserPERCENT_RANK_, ParserRANK_, ParserROW_NUMBER_, ParserGENERATED_, ParserALWAYS_, ParserSTORED_, ParserTRUE_, ParserFALSE_, ParserWINDOW_, ParserNULLS_, ParserFIRST_, ParserLAST_, ParserFILTER_, ParserGROUPS_, ParserEXCLUDE_:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(2074)
p.Keyword()
}
case ParserSTRING_LITERAL:
p.EnterOuterAlt(localctx, 3)
{
p.SetState(2075)
p.Match(ParserSTRING_LITERAL)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
case ParserOPEN_PAR:
p.EnterOuterAlt(localctx, 4)
{
p.SetState(2076)
p.Match(ParserOPEN_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
{
p.SetState(2077)
p.Any_name()
}
{
p.SetState(2078)
p.Match(ParserCLOSE_PAR)
if p.HasError() {
// Recognition error - abort rule
goto errorExit
}
}
default:
p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
goto errorExit
}
errorExit:
if p.HasError() {
v := p.GetError()
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
p.SetError(nil)
}
p.ExitRule()
return localctx
goto errorExit // Trick to prevent compiler error if the label is not used
}
func (p *Parser) Sempred(localctx antlr.RuleContext, ruleIndex, predIndex int) bool {
switch ruleIndex {
case 32:
var t *ExprContext = nil
if localctx != nil {
t = localctx.(*ExprContext)
}
return p.Expr_Sempred(t, predIndex)
default:
panic("No predicate with index: " + fmt.Sprint(ruleIndex))
}
}
func (p *Parser) Expr_Sempred(localctx antlr.RuleContext, predIndex int) bool {
switch predIndex {
case 0:
return p.Precpred(p.GetParserRuleContext(), 20)
case 1:
return p.Precpred(p.GetParserRuleContext(), 19)
case 2:
return p.Precpred(p.GetParserRuleContext(), 18)
case 3:
return p.Precpred(p.GetParserRuleContext(), 17)
case 4:
return p.Precpred(p.GetParserRuleContext(), 16)
case 5:
return p.Precpred(p.GetParserRuleContext(), 15)
case 6:
return p.Precpred(p.GetParserRuleContext(), 14)
case 7:
return p.Precpred(p.GetParserRuleContext(), 13)
case 8:
return p.Precpred(p.GetParserRuleContext(), 6)
case 9:
return p.Precpred(p.GetParserRuleContext(), 5)
case 10:
return p.Precpred(p.GetParserRuleContext(), 9)
case 11:
return p.Precpred(p.GetParserRuleContext(), 8)
case 12:
return p.Precpred(p.GetParserRuleContext(), 7)
case 13:
return p.Precpred(p.GetParserRuleContext(), 4)
default:
panic("No predicate with index: " + fmt.Sprint(predIndex))
}
}
================================================
FILE: cmd/atlas/internal/sqlparse/sqliteparse/parser_base_listener.go
================================================
// Code generated from Parser.g4 by ANTLR 4.13.1. DO NOT EDIT.
package sqliteparse // Parser
import "github.com/antlr4-go/antlr/v4"
// BaseParserListener is a complete listener for a parse tree produced by Parser.
type BaseParserListener struct{}
var _ ParserListener = &BaseParserListener{}
// VisitTerminal is called when a terminal node is visited.
func (s *BaseParserListener) VisitTerminal(node antlr.TerminalNode) {}
// VisitErrorNode is called when an error node is visited.
func (s *BaseParserListener) VisitErrorNode(node antlr.ErrorNode) {}
// EnterEveryRule is called when any rule is entered.
func (s *BaseParserListener) EnterEveryRule(ctx antlr.ParserRuleContext) {}
// ExitEveryRule is called when any rule is exited.
func (s *BaseParserListener) ExitEveryRule(ctx antlr.ParserRuleContext) {}
// EnterParse is called when production parse is entered.
func (s *BaseParserListener) EnterParse(ctx *ParseContext) {}
// ExitParse is called when production parse is exited.
func (s *BaseParserListener) ExitParse(ctx *ParseContext) {}
// EnterSql_stmt_list is called when production sql_stmt_list is entered.
func (s *BaseParserListener) EnterSql_stmt_list(ctx *Sql_stmt_listContext) {}
// ExitSql_stmt_list is called when production sql_stmt_list is exited.
func (s *BaseParserListener) ExitSql_stmt_list(ctx *Sql_stmt_listContext) {}
// EnterSql_stmt is called when production sql_stmt is entered.
func (s *BaseParserListener) EnterSql_stmt(ctx *Sql_stmtContext) {}
// ExitSql_stmt is called when production sql_stmt is exited.
func (s *BaseParserListener) ExitSql_stmt(ctx *Sql_stmtContext) {}
// EnterAlter_table_stmt is called when production alter_table_stmt is entered.
func (s *BaseParserListener) EnterAlter_table_stmt(ctx *Alter_table_stmtContext) {}
// ExitAlter_table_stmt is called when production alter_table_stmt is exited.
func (s *BaseParserListener) ExitAlter_table_stmt(ctx *Alter_table_stmtContext) {}
// EnterAnalyze_stmt is called when production analyze_stmt is entered.
func (s *BaseParserListener) EnterAnalyze_stmt(ctx *Analyze_stmtContext) {}
// ExitAnalyze_stmt is called when production analyze_stmt is exited.
func (s *BaseParserListener) ExitAnalyze_stmt(ctx *Analyze_stmtContext) {}
// EnterAttach_stmt is called when production attach_stmt is entered.
func (s *BaseParserListener) EnterAttach_stmt(ctx *Attach_stmtContext) {}
// ExitAttach_stmt is called when production attach_stmt is exited.
func (s *BaseParserListener) ExitAttach_stmt(ctx *Attach_stmtContext) {}
// EnterBegin_stmt is called when production begin_stmt is entered.
func (s *BaseParserListener) EnterBegin_stmt(ctx *Begin_stmtContext) {}
// ExitBegin_stmt is called when production begin_stmt is exited.
func (s *BaseParserListener) ExitBegin_stmt(ctx *Begin_stmtContext) {}
// EnterCommit_stmt is called when production commit_stmt is entered.
func (s *BaseParserListener) EnterCommit_stmt(ctx *Commit_stmtContext) {}
// ExitCommit_stmt is called when production commit_stmt is exited.
func (s *BaseParserListener) ExitCommit_stmt(ctx *Commit_stmtContext) {}
// EnterRollback_stmt is called when production rollback_stmt is entered.
func (s *BaseParserListener) EnterRollback_stmt(ctx *Rollback_stmtContext) {}
// ExitRollback_stmt is called when production rollback_stmt is exited.
func (s *BaseParserListener) ExitRollback_stmt(ctx *Rollback_stmtContext) {}
// EnterSavepoint_stmt is called when production savepoint_stmt is entered.
func (s *BaseParserListener) EnterSavepoint_stmt(ctx *Savepoint_stmtContext) {}
// ExitSavepoint_stmt is called when production savepoint_stmt is exited.
func (s *BaseParserListener) ExitSavepoint_stmt(ctx *Savepoint_stmtContext) {}
// EnterRelease_stmt is called when production release_stmt is entered.
func (s *BaseParserListener) EnterRelease_stmt(ctx *Release_stmtContext) {}
// ExitRelease_stmt is called when production release_stmt is exited.
func (s *BaseParserListener) ExitRelease_stmt(ctx *Release_stmtContext) {}
// EnterCreate_index_stmt is called when production create_index_stmt is entered.
func (s *BaseParserListener) EnterCreate_index_stmt(ctx *Create_index_stmtContext) {}
// ExitCreate_index_stmt is called when production create_index_stmt is exited.
func (s *BaseParserListener) ExitCreate_index_stmt(ctx *Create_index_stmtContext) {}
// EnterIndexed_column is called when production indexed_column is entered.
func (s *BaseParserListener) EnterIndexed_column(ctx *Indexed_columnContext) {}
// ExitIndexed_column is called when production indexed_column is exited.
func (s *BaseParserListener) ExitIndexed_column(ctx *Indexed_columnContext) {}
// EnterCreate_table_stmt is called when production create_table_stmt is entered.
func (s *BaseParserListener) EnterCreate_table_stmt(ctx *Create_table_stmtContext) {}
// ExitCreate_table_stmt is called when production create_table_stmt is exited.
func (s *BaseParserListener) ExitCreate_table_stmt(ctx *Create_table_stmtContext) {}
// EnterColumn_def is called when production column_def is entered.
func (s *BaseParserListener) EnterColumn_def(ctx *Column_defContext) {}
// ExitColumn_def is called when production column_def is exited.
func (s *BaseParserListener) ExitColumn_def(ctx *Column_defContext) {}
// EnterType_name is called when production type_name is entered.
func (s *BaseParserListener) EnterType_name(ctx *Type_nameContext) {}
// ExitType_name is called when production type_name is exited.
func (s *BaseParserListener) ExitType_name(ctx *Type_nameContext) {}
// EnterColumn_constraint is called when production column_constraint is entered.
func (s *BaseParserListener) EnterColumn_constraint(ctx *Column_constraintContext) {}
// ExitColumn_constraint is called when production column_constraint is exited.
func (s *BaseParserListener) ExitColumn_constraint(ctx *Column_constraintContext) {}
// EnterSigned_number is called when production signed_number is entered.
func (s *BaseParserListener) EnterSigned_number(ctx *Signed_numberContext) {}
// ExitSigned_number is called when production signed_number is exited.
func (s *BaseParserListener) ExitSigned_number(ctx *Signed_numberContext) {}
// EnterTable_constraint is called when production table_constraint is entered.
func (s *BaseParserListener) EnterTable_constraint(ctx *Table_constraintContext) {}
// ExitTable_constraint is called when production table_constraint is exited.
func (s *BaseParserListener) ExitTable_constraint(ctx *Table_constraintContext) {}
// EnterForeign_key_clause is called when production foreign_key_clause is entered.
func (s *BaseParserListener) EnterForeign_key_clause(ctx *Foreign_key_clauseContext) {}
// ExitForeign_key_clause is called when production foreign_key_clause is exited.
func (s *BaseParserListener) ExitForeign_key_clause(ctx *Foreign_key_clauseContext) {}
// EnterConflict_clause is called when production conflict_clause is entered.
func (s *BaseParserListener) EnterConflict_clause(ctx *Conflict_clauseContext) {}
// ExitConflict_clause is called when production conflict_clause is exited.
func (s *BaseParserListener) ExitConflict_clause(ctx *Conflict_clauseContext) {}
// EnterCreate_trigger_stmt is called when production create_trigger_stmt is entered.
func (s *BaseParserListener) EnterCreate_trigger_stmt(ctx *Create_trigger_stmtContext) {}
// ExitCreate_trigger_stmt is called when production create_trigger_stmt is exited.
func (s *BaseParserListener) ExitCreate_trigger_stmt(ctx *Create_trigger_stmtContext) {}
// EnterCreate_view_stmt is called when production create_view_stmt is entered.
func (s *BaseParserListener) EnterCreate_view_stmt(ctx *Create_view_stmtContext) {}
// ExitCreate_view_stmt is called when production create_view_stmt is exited.
func (s *BaseParserListener) ExitCreate_view_stmt(ctx *Create_view_stmtContext) {}
// EnterCreate_virtual_table_stmt is called when production create_virtual_table_stmt is entered.
func (s *BaseParserListener) EnterCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) {}
// ExitCreate_virtual_table_stmt is called when production create_virtual_table_stmt is exited.
func (s *BaseParserListener) ExitCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) {}
// EnterWith_clause is called when production with_clause is entered.
func (s *BaseParserListener) EnterWith_clause(ctx *With_clauseContext) {}
// ExitWith_clause is called when production with_clause is exited.
func (s *BaseParserListener) ExitWith_clause(ctx *With_clauseContext) {}
// EnterCte_table_name is called when production cte_table_name is entered.
func (s *BaseParserListener) EnterCte_table_name(ctx *Cte_table_nameContext) {}
// ExitCte_table_name is called when production cte_table_name is exited.
func (s *BaseParserListener) ExitCte_table_name(ctx *Cte_table_nameContext) {}
// EnterRecursive_cte is called when production recursive_cte is entered.
func (s *BaseParserListener) EnterRecursive_cte(ctx *Recursive_cteContext) {}
// ExitRecursive_cte is called when production recursive_cte is exited.
func (s *BaseParserListener) ExitRecursive_cte(ctx *Recursive_cteContext) {}
// EnterCommon_table_expression is called when production common_table_expression is entered.
func (s *BaseParserListener) EnterCommon_table_expression(ctx *Common_table_expressionContext) {}
// ExitCommon_table_expression is called when production common_table_expression is exited.
func (s *BaseParserListener) ExitCommon_table_expression(ctx *Common_table_expressionContext) {}
// EnterDelete_stmt is called when production delete_stmt is entered.
func (s *BaseParserListener) EnterDelete_stmt(ctx *Delete_stmtContext) {}
// ExitDelete_stmt is called when production delete_stmt is exited.
func (s *BaseParserListener) ExitDelete_stmt(ctx *Delete_stmtContext) {}
// EnterDelete_stmt_limited is called when production delete_stmt_limited is entered.
func (s *BaseParserListener) EnterDelete_stmt_limited(ctx *Delete_stmt_limitedContext) {}
// ExitDelete_stmt_limited is called when production delete_stmt_limited is exited.
func (s *BaseParserListener) ExitDelete_stmt_limited(ctx *Delete_stmt_limitedContext) {}
// EnterDetach_stmt is called when production detach_stmt is entered.
func (s *BaseParserListener) EnterDetach_stmt(ctx *Detach_stmtContext) {}
// ExitDetach_stmt is called when production detach_stmt is exited.
func (s *BaseParserListener) ExitDetach_stmt(ctx *Detach_stmtContext) {}
// EnterDrop_stmt is called when production drop_stmt is entered.
func (s *BaseParserListener) EnterDrop_stmt(ctx *Drop_stmtContext) {}
// ExitDrop_stmt is called when production drop_stmt is exited.
func (s *BaseParserListener) ExitDrop_stmt(ctx *Drop_stmtContext) {}
// EnterExpr is called when production expr is entered.
func (s *BaseParserListener) EnterExpr(ctx *ExprContext) {}
// ExitExpr is called when production expr is exited.
func (s *BaseParserListener) ExitExpr(ctx *ExprContext) {}
// EnterRaise_function is called when production raise_function is entered.
func (s *BaseParserListener) EnterRaise_function(ctx *Raise_functionContext) {}
// ExitRaise_function is called when production raise_function is exited.
func (s *BaseParserListener) ExitRaise_function(ctx *Raise_functionContext) {}
// EnterLiteral_value is called when production literal_value is entered.
func (s *BaseParserListener) EnterLiteral_value(ctx *Literal_valueContext) {}
// ExitLiteral_value is called when production literal_value is exited.
func (s *BaseParserListener) ExitLiteral_value(ctx *Literal_valueContext) {}
// EnterInsert_stmt is called when production insert_stmt is entered.
func (s *BaseParserListener) EnterInsert_stmt(ctx *Insert_stmtContext) {}
// ExitInsert_stmt is called when production insert_stmt is exited.
func (s *BaseParserListener) ExitInsert_stmt(ctx *Insert_stmtContext) {}
// EnterReturning_clause is called when production returning_clause is entered.
func (s *BaseParserListener) EnterReturning_clause(ctx *Returning_clauseContext) {}
// ExitReturning_clause is called when production returning_clause is exited.
func (s *BaseParserListener) ExitReturning_clause(ctx *Returning_clauseContext) {}
// EnterUpsert_clause is called when production upsert_clause is entered.
func (s *BaseParserListener) EnterUpsert_clause(ctx *Upsert_clauseContext) {}
// ExitUpsert_clause is called when production upsert_clause is exited.
func (s *BaseParserListener) ExitUpsert_clause(ctx *Upsert_clauseContext) {}
// EnterPragma_stmt is called when production pragma_stmt is entered.
func (s *BaseParserListener) EnterPragma_stmt(ctx *Pragma_stmtContext) {}
// ExitPragma_stmt is called when production pragma_stmt is exited.
func (s *BaseParserListener) ExitPragma_stmt(ctx *Pragma_stmtContext) {}
// EnterPragma_value is called when production pragma_value is entered.
func (s *BaseParserListener) EnterPragma_value(ctx *Pragma_valueContext) {}
// ExitPragma_value is called when production pragma_value is exited.
func (s *BaseParserListener) ExitPragma_value(ctx *Pragma_valueContext) {}
// EnterReindex_stmt is called when production reindex_stmt is entered.
func (s *BaseParserListener) EnterReindex_stmt(ctx *Reindex_stmtContext) {}
// ExitReindex_stmt is called when production reindex_stmt is exited.
func (s *BaseParserListener) ExitReindex_stmt(ctx *Reindex_stmtContext) {}
// EnterSelect_stmt is called when production select_stmt is entered.
func (s *BaseParserListener) EnterSelect_stmt(ctx *Select_stmtContext) {}
// ExitSelect_stmt is called when production select_stmt is exited.
func (s *BaseParserListener) ExitSelect_stmt(ctx *Select_stmtContext) {}
// EnterJoin_clause is called when production join_clause is entered.
func (s *BaseParserListener) EnterJoin_clause(ctx *Join_clauseContext) {}
// ExitJoin_clause is called when production join_clause is exited.
func (s *BaseParserListener) ExitJoin_clause(ctx *Join_clauseContext) {}
// EnterSelect_core is called when production select_core is entered.
func (s *BaseParserListener) EnterSelect_core(ctx *Select_coreContext) {}
// ExitSelect_core is called when production select_core is exited.
func (s *BaseParserListener) ExitSelect_core(ctx *Select_coreContext) {}
// EnterFactored_select_stmt is called when production factored_select_stmt is entered.
func (s *BaseParserListener) EnterFactored_select_stmt(ctx *Factored_select_stmtContext) {}
// ExitFactored_select_stmt is called when production factored_select_stmt is exited.
func (s *BaseParserListener) ExitFactored_select_stmt(ctx *Factored_select_stmtContext) {}
// EnterSimple_select_stmt is called when production simple_select_stmt is entered.
func (s *BaseParserListener) EnterSimple_select_stmt(ctx *Simple_select_stmtContext) {}
// ExitSimple_select_stmt is called when production simple_select_stmt is exited.
func (s *BaseParserListener) ExitSimple_select_stmt(ctx *Simple_select_stmtContext) {}
// EnterCompound_select_stmt is called when production compound_select_stmt is entered.
func (s *BaseParserListener) EnterCompound_select_stmt(ctx *Compound_select_stmtContext) {}
// ExitCompound_select_stmt is called when production compound_select_stmt is exited.
func (s *BaseParserListener) ExitCompound_select_stmt(ctx *Compound_select_stmtContext) {}
// EnterTable_or_subquery is called when production table_or_subquery is entered.
func (s *BaseParserListener) EnterTable_or_subquery(ctx *Table_or_subqueryContext) {}
// ExitTable_or_subquery is called when production table_or_subquery is exited.
func (s *BaseParserListener) ExitTable_or_subquery(ctx *Table_or_subqueryContext) {}
// EnterResult_column is called when production result_column is entered.
func (s *BaseParserListener) EnterResult_column(ctx *Result_columnContext) {}
// ExitResult_column is called when production result_column is exited.
func (s *BaseParserListener) ExitResult_column(ctx *Result_columnContext) {}
// EnterJoin_operator is called when production join_operator is entered.
func (s *BaseParserListener) EnterJoin_operator(ctx *Join_operatorContext) {}
// ExitJoin_operator is called when production join_operator is exited.
func (s *BaseParserListener) ExitJoin_operator(ctx *Join_operatorContext) {}
// EnterJoin_constraint is called when production join_constraint is entered.
func (s *BaseParserListener) EnterJoin_constraint(ctx *Join_constraintContext) {}
// ExitJoin_constraint is called when production join_constraint is exited.
func (s *BaseParserListener) ExitJoin_constraint(ctx *Join_constraintContext) {}
// EnterCompound_operator is called when production compound_operator is entered.
func (s *BaseParserListener) EnterCompound_operator(ctx *Compound_operatorContext) {}
// ExitCompound_operator is called when production compound_operator is exited.
func (s *BaseParserListener) ExitCompound_operator(ctx *Compound_operatorContext) {}
// EnterUpdate_stmt is called when production update_stmt is entered.
func (s *BaseParserListener) EnterUpdate_stmt(ctx *Update_stmtContext) {}
// ExitUpdate_stmt is called when production update_stmt is exited.
func (s *BaseParserListener) ExitUpdate_stmt(ctx *Update_stmtContext) {}
// EnterAssignment_list is called when production assignment_list is entered.
func (s *BaseParserListener) EnterAssignment_list(ctx *Assignment_listContext) {}
// ExitAssignment_list is called when production assignment_list is exited.
func (s *BaseParserListener) ExitAssignment_list(ctx *Assignment_listContext) {}
// EnterAssignment is called when production assignment is entered.
func (s *BaseParserListener) EnterAssignment(ctx *AssignmentContext) {}
// ExitAssignment is called when production assignment is exited.
func (s *BaseParserListener) ExitAssignment(ctx *AssignmentContext) {}
// EnterColumn_name_list is called when production column_name_list is entered.
func (s *BaseParserListener) EnterColumn_name_list(ctx *Column_name_listContext) {}
// ExitColumn_name_list is called when production column_name_list is exited.
func (s *BaseParserListener) ExitColumn_name_list(ctx *Column_name_listContext) {}
// EnterUpdate_stmt_limited is called when production update_stmt_limited is entered.
func (s *BaseParserListener) EnterUpdate_stmt_limited(ctx *Update_stmt_limitedContext) {}
// ExitUpdate_stmt_limited is called when production update_stmt_limited is exited.
func (s *BaseParserListener) ExitUpdate_stmt_limited(ctx *Update_stmt_limitedContext) {}
// EnterQualified_table_name is called when production qualified_table_name is entered.
func (s *BaseParserListener) EnterQualified_table_name(ctx *Qualified_table_nameContext) {}
// ExitQualified_table_name is called when production qualified_table_name is exited.
func (s *BaseParserListener) ExitQualified_table_name(ctx *Qualified_table_nameContext) {}
// EnterVacuum_stmt is called when production vacuum_stmt is entered.
func (s *BaseParserListener) EnterVacuum_stmt(ctx *Vacuum_stmtContext) {}
// ExitVacuum_stmt is called when production vacuum_stmt is exited.
func (s *BaseParserListener) ExitVacuum_stmt(ctx *Vacuum_stmtContext) {}
// EnterFilter_clause is called when production filter_clause is entered.
func (s *BaseParserListener) EnterFilter_clause(ctx *Filter_clauseContext) {}
// ExitFilter_clause is called when production filter_clause is exited.
func (s *BaseParserListener) ExitFilter_clause(ctx *Filter_clauseContext) {}
// EnterWindow_defn is called when production window_defn is entered.
func (s *BaseParserListener) EnterWindow_defn(ctx *Window_defnContext) {}
// ExitWindow_defn is called when production window_defn is exited.
func (s *BaseParserListener) ExitWindow_defn(ctx *Window_defnContext) {}
// EnterOver_clause is called when production over_clause is entered.
func (s *BaseParserListener) EnterOver_clause(ctx *Over_clauseContext) {}
// ExitOver_clause is called when production over_clause is exited.
func (s *BaseParserListener) ExitOver_clause(ctx *Over_clauseContext) {}
// EnterFrame_spec is called when production frame_spec is entered.
func (s *BaseParserListener) EnterFrame_spec(ctx *Frame_specContext) {}
// ExitFrame_spec is called when production frame_spec is exited.
func (s *BaseParserListener) ExitFrame_spec(ctx *Frame_specContext) {}
// EnterFrame_clause is called when production frame_clause is entered.
func (s *BaseParserListener) EnterFrame_clause(ctx *Frame_clauseContext) {}
// ExitFrame_clause is called when production frame_clause is exited.
func (s *BaseParserListener) ExitFrame_clause(ctx *Frame_clauseContext) {}
// EnterSimple_function_invocation is called when production simple_function_invocation is entered.
func (s *BaseParserListener) EnterSimple_function_invocation(ctx *Simple_function_invocationContext) {
}
// ExitSimple_function_invocation is called when production simple_function_invocation is exited.
func (s *BaseParserListener) ExitSimple_function_invocation(ctx *Simple_function_invocationContext) {}
// EnterAggregate_function_invocation is called when production aggregate_function_invocation is entered.
func (s *BaseParserListener) EnterAggregate_function_invocation(ctx *Aggregate_function_invocationContext) {
}
// ExitAggregate_function_invocation is called when production aggregate_function_invocation is exited.
func (s *BaseParserListener) ExitAggregate_function_invocation(ctx *Aggregate_function_invocationContext) {
}
// EnterWindow_function_invocation is called when production window_function_invocation is entered.
func (s *BaseParserListener) EnterWindow_function_invocation(ctx *Window_function_invocationContext) {
}
// ExitWindow_function_invocation is called when production window_function_invocation is exited.
func (s *BaseParserListener) ExitWindow_function_invocation(ctx *Window_function_invocationContext) {}
// EnterCommon_table_stmt is called when production common_table_stmt is entered.
func (s *BaseParserListener) EnterCommon_table_stmt(ctx *Common_table_stmtContext) {}
// ExitCommon_table_stmt is called when production common_table_stmt is exited.
func (s *BaseParserListener) ExitCommon_table_stmt(ctx *Common_table_stmtContext) {}
// EnterOrder_by_stmt is called when production order_by_stmt is entered.
func (s *BaseParserListener) EnterOrder_by_stmt(ctx *Order_by_stmtContext) {}
// ExitOrder_by_stmt is called when production order_by_stmt is exited.
func (s *BaseParserListener) ExitOrder_by_stmt(ctx *Order_by_stmtContext) {}
// EnterLimit_stmt is called when production limit_stmt is entered.
func (s *BaseParserListener) EnterLimit_stmt(ctx *Limit_stmtContext) {}
// ExitLimit_stmt is called when production limit_stmt is exited.
func (s *BaseParserListener) ExitLimit_stmt(ctx *Limit_stmtContext) {}
// EnterOrdering_term is called when production ordering_term is entered.
func (s *BaseParserListener) EnterOrdering_term(ctx *Ordering_termContext) {}
// ExitOrdering_term is called when production ordering_term is exited.
func (s *BaseParserListener) ExitOrdering_term(ctx *Ordering_termContext) {}
// EnterAsc_desc is called when production asc_desc is entered.
func (s *BaseParserListener) EnterAsc_desc(ctx *Asc_descContext) {}
// ExitAsc_desc is called when production asc_desc is exited.
func (s *BaseParserListener) ExitAsc_desc(ctx *Asc_descContext) {}
// EnterFrame_left is called when production frame_left is entered.
func (s *BaseParserListener) EnterFrame_left(ctx *Frame_leftContext) {}
// ExitFrame_left is called when production frame_left is exited.
func (s *BaseParserListener) ExitFrame_left(ctx *Frame_leftContext) {}
// EnterFrame_right is called when production frame_right is entered.
func (s *BaseParserListener) EnterFrame_right(ctx *Frame_rightContext) {}
// ExitFrame_right is called when production frame_right is exited.
func (s *BaseParserListener) ExitFrame_right(ctx *Frame_rightContext) {}
// EnterFrame_single is called when production frame_single is entered.
func (s *BaseParserListener) EnterFrame_single(ctx *Frame_singleContext) {}
// ExitFrame_single is called when production frame_single is exited.
func (s *BaseParserListener) ExitFrame_single(ctx *Frame_singleContext) {}
// EnterWindow_function is called when production window_function is entered.
func (s *BaseParserListener) EnterWindow_function(ctx *Window_functionContext) {}
// ExitWindow_function is called when production window_function is exited.
func (s *BaseParserListener) ExitWindow_function(ctx *Window_functionContext) {}
// EnterOffset is called when production offset is entered.
func (s *BaseParserListener) EnterOffset(ctx *OffsetContext) {}
// ExitOffset is called when production offset is exited.
func (s *BaseParserListener) ExitOffset(ctx *OffsetContext) {}
// EnterDefault_value is called when production default_value is entered.
func (s *BaseParserListener) EnterDefault_value(ctx *Default_valueContext) {}
// ExitDefault_value is called when production default_value is exited.
func (s *BaseParserListener) ExitDefault_value(ctx *Default_valueContext) {}
// EnterPartition_by is called when production partition_by is entered.
func (s *BaseParserListener) EnterPartition_by(ctx *Partition_byContext) {}
// ExitPartition_by is called when production partition_by is exited.
func (s *BaseParserListener) ExitPartition_by(ctx *Partition_byContext) {}
// EnterOrder_by_expr is called when production order_by_expr is entered.
func (s *BaseParserListener) EnterOrder_by_expr(ctx *Order_by_exprContext) {}
// ExitOrder_by_expr is called when production order_by_expr is exited.
func (s *BaseParserListener) ExitOrder_by_expr(ctx *Order_by_exprContext) {}
// EnterOrder_by_expr_asc_desc is called when production order_by_expr_asc_desc is entered.
func (s *BaseParserListener) EnterOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) {}
// ExitOrder_by_expr_asc_desc is called when production order_by_expr_asc_desc is exited.
func (s *BaseParserListener) ExitOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) {}
// EnterExpr_asc_desc is called when production expr_asc_desc is entered.
func (s *BaseParserListener) EnterExpr_asc_desc(ctx *Expr_asc_descContext) {}
// ExitExpr_asc_desc is called when production expr_asc_desc is exited.
func (s *BaseParserListener) ExitExpr_asc_desc(ctx *Expr_asc_descContext) {}
// EnterInitial_select is called when production initial_select is entered.
func (s *BaseParserListener) EnterInitial_select(ctx *Initial_selectContext) {}
// ExitInitial_select is called when production initial_select is exited.
func (s *BaseParserListener) ExitInitial_select(ctx *Initial_selectContext) {}
// EnterRecursive_select is called when production recursive_select is entered.
func (s *BaseParserListener) EnterRecursive_select(ctx *Recursive_selectContext) {}
// ExitRecursive_select is called when production recursive_select is exited.
func (s *BaseParserListener) ExitRecursive_select(ctx *Recursive_selectContext) {}
// EnterUnary_operator is called when production unary_operator is entered.
func (s *BaseParserListener) EnterUnary_operator(ctx *Unary_operatorContext) {}
// ExitUnary_operator is called when production unary_operator is exited.
func (s *BaseParserListener) ExitUnary_operator(ctx *Unary_operatorContext) {}
// EnterError_message is called when production error_message is entered.
func (s *BaseParserListener) EnterError_message(ctx *Error_messageContext) {}
// ExitError_message is called when production error_message is exited.
func (s *BaseParserListener) ExitError_message(ctx *Error_messageContext) {}
// EnterModule_argument is called when production module_argument is entered.
func (s *BaseParserListener) EnterModule_argument(ctx *Module_argumentContext) {}
// ExitModule_argument is called when production module_argument is exited.
func (s *BaseParserListener) ExitModule_argument(ctx *Module_argumentContext) {}
// EnterColumn_alias is called when production column_alias is entered.
func (s *BaseParserListener) EnterColumn_alias(ctx *Column_aliasContext) {}
// ExitColumn_alias is called when production column_alias is exited.
func (s *BaseParserListener) ExitColumn_alias(ctx *Column_aliasContext) {}
// EnterKeyword is called when production keyword is entered.
func (s *BaseParserListener) EnterKeyword(ctx *KeywordContext) {}
// ExitKeyword is called when production keyword is exited.
func (s *BaseParserListener) ExitKeyword(ctx *KeywordContext) {}
// EnterName is called when production name is entered.
func (s *BaseParserListener) EnterName(ctx *NameContext) {}
// ExitName is called when production name is exited.
func (s *BaseParserListener) ExitName(ctx *NameContext) {}
// EnterFunction_name is called when production function_name is entered.
func (s *BaseParserListener) EnterFunction_name(ctx *Function_nameContext) {}
// ExitFunction_name is called when production function_name is exited.
func (s *BaseParserListener) ExitFunction_name(ctx *Function_nameContext) {}
// EnterSchema_name is called when production schema_name is entered.
func (s *BaseParserListener) EnterSchema_name(ctx *Schema_nameContext) {}
// ExitSchema_name is called when production schema_name is exited.
func (s *BaseParserListener) ExitSchema_name(ctx *Schema_nameContext) {}
// EnterTable_name is called when production table_name is entered.
func (s *BaseParserListener) EnterTable_name(ctx *Table_nameContext) {}
// ExitTable_name is called when production table_name is exited.
func (s *BaseParserListener) ExitTable_name(ctx *Table_nameContext) {}
// EnterTable_or_index_name is called when production table_or_index_name is entered.
func (s *BaseParserListener) EnterTable_or_index_name(ctx *Table_or_index_nameContext) {}
// ExitTable_or_index_name is called when production table_or_index_name is exited.
func (s *BaseParserListener) ExitTable_or_index_name(ctx *Table_or_index_nameContext) {}
// EnterColumn_name is called when production column_name is entered.
func (s *BaseParserListener) EnterColumn_name(ctx *Column_nameContext) {}
// ExitColumn_name is called when production column_name is exited.
func (s *BaseParserListener) ExitColumn_name(ctx *Column_nameContext) {}
// EnterCollation_name is called when production collation_name is entered.
func (s *BaseParserListener) EnterCollation_name(ctx *Collation_nameContext) {}
// ExitCollation_name is called when production collation_name is exited.
func (s *BaseParserListener) ExitCollation_name(ctx *Collation_nameContext) {}
// EnterForeign_table is called when production foreign_table is entered.
func (s *BaseParserListener) EnterForeign_table(ctx *Foreign_tableContext) {}
// ExitForeign_table is called when production foreign_table is exited.
func (s *BaseParserListener) ExitForeign_table(ctx *Foreign_tableContext) {}
// EnterIndex_name is called when production index_name is entered.
func (s *BaseParserListener) EnterIndex_name(ctx *Index_nameContext) {}
// ExitIndex_name is called when production index_name is exited.
func (s *BaseParserListener) ExitIndex_name(ctx *Index_nameContext) {}
// EnterTrigger_name is called when production trigger_name is entered.
func (s *BaseParserListener) EnterTrigger_name(ctx *Trigger_nameContext) {}
// ExitTrigger_name is called when production trigger_name is exited.
func (s *BaseParserListener) ExitTrigger_name(ctx *Trigger_nameContext) {}
// EnterView_name is called when production view_name is entered.
func (s *BaseParserListener) EnterView_name(ctx *View_nameContext) {}
// ExitView_name is called when production view_name is exited.
func (s *BaseParserListener) ExitView_name(ctx *View_nameContext) {}
// EnterModule_name is called when production module_name is entered.
func (s *BaseParserListener) EnterModule_name(ctx *Module_nameContext) {}
// ExitModule_name is called when production module_name is exited.
func (s *BaseParserListener) ExitModule_name(ctx *Module_nameContext) {}
// EnterPragma_name is called when production pragma_name is entered.
func (s *BaseParserListener) EnterPragma_name(ctx *Pragma_nameContext) {}
// ExitPragma_name is called when production pragma_name is exited.
func (s *BaseParserListener) ExitPragma_name(ctx *Pragma_nameContext) {}
// EnterSavepoint_name is called when production savepoint_name is entered.
func (s *BaseParserListener) EnterSavepoint_name(ctx *Savepoint_nameContext) {}
// ExitSavepoint_name is called when production savepoint_name is exited.
func (s *BaseParserListener) ExitSavepoint_name(ctx *Savepoint_nameContext) {}
// EnterTable_alias is called when production table_alias is entered.
func (s *BaseParserListener) EnterTable_alias(ctx *Table_aliasContext) {}
// ExitTable_alias is called when production table_alias is exited.
func (s *BaseParserListener) ExitTable_alias(ctx *Table_aliasContext) {}
// EnterTransaction_name is called when production transaction_name is entered.
func (s *BaseParserListener) EnterTransaction_name(ctx *Transaction_nameContext) {}
// ExitTransaction_name is called when production transaction_name is exited.
func (s *BaseParserListener) ExitTransaction_name(ctx *Transaction_nameContext) {}
// EnterWindow_name is called when production window_name is entered.
func (s *BaseParserListener) EnterWindow_name(ctx *Window_nameContext) {}
// ExitWindow_name is called when production window_name is exited.
func (s *BaseParserListener) ExitWindow_name(ctx *Window_nameContext) {}
// EnterAlias is called when production alias is entered.
func (s *BaseParserListener) EnterAlias(ctx *AliasContext) {}
// ExitAlias is called when production alias is exited.
func (s *BaseParserListener) ExitAlias(ctx *AliasContext) {}
// EnterFilename is called when production filename is entered.
func (s *BaseParserListener) EnterFilename(ctx *FilenameContext) {}
// ExitFilename is called when production filename is exited.
func (s *BaseParserListener) ExitFilename(ctx *FilenameContext) {}
// EnterBase_window_name is called when production base_window_name is entered.
func (s *BaseParserListener) EnterBase_window_name(ctx *Base_window_nameContext) {}
// ExitBase_window_name is called when production base_window_name is exited.
func (s *BaseParserListener) ExitBase_window_name(ctx *Base_window_nameContext) {}
// EnterSimple_func is called when production simple_func is entered.
func (s *BaseParserListener) EnterSimple_func(ctx *Simple_funcContext) {}
// ExitSimple_func is called when production simple_func is exited.
func (s *BaseParserListener) ExitSimple_func(ctx *Simple_funcContext) {}
// EnterAggregate_func is called when production aggregate_func is entered.
func (s *BaseParserListener) EnterAggregate_func(ctx *Aggregate_funcContext) {}
// ExitAggregate_func is called when production aggregate_func is exited.
func (s *BaseParserListener) ExitAggregate_func(ctx *Aggregate_funcContext) {}
// EnterTable_function_name is called when production table_function_name is entered.
func (s *BaseParserListener) EnterTable_function_name(ctx *Table_function_nameContext) {}
// ExitTable_function_name is called when production table_function_name is exited.
func (s *BaseParserListener) ExitTable_function_name(ctx *Table_function_nameContext) {}
// EnterAny_name is called when production any_name is entered.
func (s *BaseParserListener) EnterAny_name(ctx *Any_nameContext) {}
// ExitAny_name is called when production any_name is exited.
func (s *BaseParserListener) ExitAny_name(ctx *Any_nameContext) {}
================================================
FILE: cmd/atlas/internal/sqlparse/sqliteparse/parser_base_visitor.go
================================================
// Code generated from Parser.g4 by ANTLR 4.13.1. DO NOT EDIT.
package sqliteparse // Parser
import "github.com/antlr4-go/antlr/v4"
type BaseParserVisitor struct {
*antlr.BaseParseTreeVisitor
}
func (v *BaseParserVisitor) VisitParse(ctx *ParseContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitSql_stmt_list(ctx *Sql_stmt_listContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitSql_stmt(ctx *Sql_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitAlter_table_stmt(ctx *Alter_table_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitAnalyze_stmt(ctx *Analyze_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitAttach_stmt(ctx *Attach_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitBegin_stmt(ctx *Begin_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCommit_stmt(ctx *Commit_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitRollback_stmt(ctx *Rollback_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitSavepoint_stmt(ctx *Savepoint_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitRelease_stmt(ctx *Release_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCreate_index_stmt(ctx *Create_index_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitIndexed_column(ctx *Indexed_columnContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCreate_table_stmt(ctx *Create_table_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitColumn_def(ctx *Column_defContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitType_name(ctx *Type_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitColumn_constraint(ctx *Column_constraintContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitSigned_number(ctx *Signed_numberContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitTable_constraint(ctx *Table_constraintContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitForeign_key_clause(ctx *Foreign_key_clauseContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitConflict_clause(ctx *Conflict_clauseContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCreate_trigger_stmt(ctx *Create_trigger_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCreate_view_stmt(ctx *Create_view_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitWith_clause(ctx *With_clauseContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCte_table_name(ctx *Cte_table_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitRecursive_cte(ctx *Recursive_cteContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCommon_table_expression(ctx *Common_table_expressionContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitDelete_stmt(ctx *Delete_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitDelete_stmt_limited(ctx *Delete_stmt_limitedContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitDetach_stmt(ctx *Detach_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitDrop_stmt(ctx *Drop_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitExpr(ctx *ExprContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitRaise_function(ctx *Raise_functionContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitLiteral_value(ctx *Literal_valueContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitInsert_stmt(ctx *Insert_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitReturning_clause(ctx *Returning_clauseContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitUpsert_clause(ctx *Upsert_clauseContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitPragma_stmt(ctx *Pragma_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitPragma_value(ctx *Pragma_valueContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitReindex_stmt(ctx *Reindex_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitSelect_stmt(ctx *Select_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitJoin_clause(ctx *Join_clauseContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitSelect_core(ctx *Select_coreContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitFactored_select_stmt(ctx *Factored_select_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitSimple_select_stmt(ctx *Simple_select_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCompound_select_stmt(ctx *Compound_select_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitTable_or_subquery(ctx *Table_or_subqueryContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitResult_column(ctx *Result_columnContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitJoin_operator(ctx *Join_operatorContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitJoin_constraint(ctx *Join_constraintContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCompound_operator(ctx *Compound_operatorContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitUpdate_stmt(ctx *Update_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitAssignment_list(ctx *Assignment_listContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitAssignment(ctx *AssignmentContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitColumn_name_list(ctx *Column_name_listContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitUpdate_stmt_limited(ctx *Update_stmt_limitedContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitQualified_table_name(ctx *Qualified_table_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitVacuum_stmt(ctx *Vacuum_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitFilter_clause(ctx *Filter_clauseContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitWindow_defn(ctx *Window_defnContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitOver_clause(ctx *Over_clauseContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitFrame_spec(ctx *Frame_specContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitFrame_clause(ctx *Frame_clauseContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitSimple_function_invocation(ctx *Simple_function_invocationContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitAggregate_function_invocation(ctx *Aggregate_function_invocationContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitWindow_function_invocation(ctx *Window_function_invocationContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCommon_table_stmt(ctx *Common_table_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitOrder_by_stmt(ctx *Order_by_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitLimit_stmt(ctx *Limit_stmtContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitOrdering_term(ctx *Ordering_termContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitAsc_desc(ctx *Asc_descContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitFrame_left(ctx *Frame_leftContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitFrame_right(ctx *Frame_rightContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitFrame_single(ctx *Frame_singleContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitWindow_function(ctx *Window_functionContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitOffset(ctx *OffsetContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitDefault_value(ctx *Default_valueContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitPartition_by(ctx *Partition_byContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitOrder_by_expr(ctx *Order_by_exprContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitExpr_asc_desc(ctx *Expr_asc_descContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitInitial_select(ctx *Initial_selectContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitRecursive_select(ctx *Recursive_selectContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitUnary_operator(ctx *Unary_operatorContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitError_message(ctx *Error_messageContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitModule_argument(ctx *Module_argumentContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitColumn_alias(ctx *Column_aliasContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitKeyword(ctx *KeywordContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitName(ctx *NameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitFunction_name(ctx *Function_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitSchema_name(ctx *Schema_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitTable_name(ctx *Table_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitTable_or_index_name(ctx *Table_or_index_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitColumn_name(ctx *Column_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitCollation_name(ctx *Collation_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitForeign_table(ctx *Foreign_tableContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitIndex_name(ctx *Index_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitTrigger_name(ctx *Trigger_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitView_name(ctx *View_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitModule_name(ctx *Module_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitPragma_name(ctx *Pragma_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitSavepoint_name(ctx *Savepoint_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitTable_alias(ctx *Table_aliasContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitTransaction_name(ctx *Transaction_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitWindow_name(ctx *Window_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitAlias(ctx *AliasContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitFilename(ctx *FilenameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitBase_window_name(ctx *Base_window_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitSimple_func(ctx *Simple_funcContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitAggregate_func(ctx *Aggregate_funcContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitTable_function_name(ctx *Table_function_nameContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BaseParserVisitor) VisitAny_name(ctx *Any_nameContext) interface{} {
return v.VisitChildren(ctx)
}
================================================
FILE: cmd/atlas/internal/sqlparse/sqliteparse/parser_listener.go
================================================
// Code generated from Parser.g4 by ANTLR 4.13.1. DO NOT EDIT.
package sqliteparse // Parser
import "github.com/antlr4-go/antlr/v4"
// ParserListener is a complete listener for a parse tree produced by Parser.
type ParserListener interface {
antlr.ParseTreeListener
// EnterParse is called when entering the parse production.
EnterParse(c *ParseContext)
// EnterSql_stmt_list is called when entering the sql_stmt_list production.
EnterSql_stmt_list(c *Sql_stmt_listContext)
// EnterSql_stmt is called when entering the sql_stmt production.
EnterSql_stmt(c *Sql_stmtContext)
// EnterAlter_table_stmt is called when entering the alter_table_stmt production.
EnterAlter_table_stmt(c *Alter_table_stmtContext)
// EnterAnalyze_stmt is called when entering the analyze_stmt production.
EnterAnalyze_stmt(c *Analyze_stmtContext)
// EnterAttach_stmt is called when entering the attach_stmt production.
EnterAttach_stmt(c *Attach_stmtContext)
// EnterBegin_stmt is called when entering the begin_stmt production.
EnterBegin_stmt(c *Begin_stmtContext)
// EnterCommit_stmt is called when entering the commit_stmt production.
EnterCommit_stmt(c *Commit_stmtContext)
// EnterRollback_stmt is called when entering the rollback_stmt production.
EnterRollback_stmt(c *Rollback_stmtContext)
// EnterSavepoint_stmt is called when entering the savepoint_stmt production.
EnterSavepoint_stmt(c *Savepoint_stmtContext)
// EnterRelease_stmt is called when entering the release_stmt production.
EnterRelease_stmt(c *Release_stmtContext)
// EnterCreate_index_stmt is called when entering the create_index_stmt production.
EnterCreate_index_stmt(c *Create_index_stmtContext)
// EnterIndexed_column is called when entering the indexed_column production.
EnterIndexed_column(c *Indexed_columnContext)
// EnterCreate_table_stmt is called when entering the create_table_stmt production.
EnterCreate_table_stmt(c *Create_table_stmtContext)
// EnterColumn_def is called when entering the column_def production.
EnterColumn_def(c *Column_defContext)
// EnterType_name is called when entering the type_name production.
EnterType_name(c *Type_nameContext)
// EnterColumn_constraint is called when entering the column_constraint production.
EnterColumn_constraint(c *Column_constraintContext)
// EnterSigned_number is called when entering the signed_number production.
EnterSigned_number(c *Signed_numberContext)
// EnterTable_constraint is called when entering the table_constraint production.
EnterTable_constraint(c *Table_constraintContext)
// EnterForeign_key_clause is called when entering the foreign_key_clause production.
EnterForeign_key_clause(c *Foreign_key_clauseContext)
// EnterConflict_clause is called when entering the conflict_clause production.
EnterConflict_clause(c *Conflict_clauseContext)
// EnterCreate_trigger_stmt is called when entering the create_trigger_stmt production.
EnterCreate_trigger_stmt(c *Create_trigger_stmtContext)
// EnterCreate_view_stmt is called when entering the create_view_stmt production.
EnterCreate_view_stmt(c *Create_view_stmtContext)
// EnterCreate_virtual_table_stmt is called when entering the create_virtual_table_stmt production.
EnterCreate_virtual_table_stmt(c *Create_virtual_table_stmtContext)
// EnterWith_clause is called when entering the with_clause production.
EnterWith_clause(c *With_clauseContext)
// EnterCte_table_name is called when entering the cte_table_name production.
EnterCte_table_name(c *Cte_table_nameContext)
// EnterRecursive_cte is called when entering the recursive_cte production.
EnterRecursive_cte(c *Recursive_cteContext)
// EnterCommon_table_expression is called when entering the common_table_expression production.
EnterCommon_table_expression(c *Common_table_expressionContext)
// EnterDelete_stmt is called when entering the delete_stmt production.
EnterDelete_stmt(c *Delete_stmtContext)
// EnterDelete_stmt_limited is called when entering the delete_stmt_limited production.
EnterDelete_stmt_limited(c *Delete_stmt_limitedContext)
// EnterDetach_stmt is called when entering the detach_stmt production.
EnterDetach_stmt(c *Detach_stmtContext)
// EnterDrop_stmt is called when entering the drop_stmt production.
EnterDrop_stmt(c *Drop_stmtContext)
// EnterExpr is called when entering the expr production.
EnterExpr(c *ExprContext)
// EnterRaise_function is called when entering the raise_function production.
EnterRaise_function(c *Raise_functionContext)
// EnterLiteral_value is called when entering the literal_value production.
EnterLiteral_value(c *Literal_valueContext)
// EnterInsert_stmt is called when entering the insert_stmt production.
EnterInsert_stmt(c *Insert_stmtContext)
// EnterReturning_clause is called when entering the returning_clause production.
EnterReturning_clause(c *Returning_clauseContext)
// EnterUpsert_clause is called when entering the upsert_clause production.
EnterUpsert_clause(c *Upsert_clauseContext)
// EnterPragma_stmt is called when entering the pragma_stmt production.
EnterPragma_stmt(c *Pragma_stmtContext)
// EnterPragma_value is called when entering the pragma_value production.
EnterPragma_value(c *Pragma_valueContext)
// EnterReindex_stmt is called when entering the reindex_stmt production.
EnterReindex_stmt(c *Reindex_stmtContext)
// EnterSelect_stmt is called when entering the select_stmt production.
EnterSelect_stmt(c *Select_stmtContext)
// EnterJoin_clause is called when entering the join_clause production.
EnterJoin_clause(c *Join_clauseContext)
// EnterSelect_core is called when entering the select_core production.
EnterSelect_core(c *Select_coreContext)
// EnterFactored_select_stmt is called when entering the factored_select_stmt production.
EnterFactored_select_stmt(c *Factored_select_stmtContext)
// EnterSimple_select_stmt is called when entering the simple_select_stmt production.
EnterSimple_select_stmt(c *Simple_select_stmtContext)
// EnterCompound_select_stmt is called when entering the compound_select_stmt production.
EnterCompound_select_stmt(c *Compound_select_stmtContext)
// EnterTable_or_subquery is called when entering the table_or_subquery production.
EnterTable_or_subquery(c *Table_or_subqueryContext)
// EnterResult_column is called when entering the result_column production.
EnterResult_column(c *Result_columnContext)
// EnterJoin_operator is called when entering the join_operator production.
EnterJoin_operator(c *Join_operatorContext)
// EnterJoin_constraint is called when entering the join_constraint production.
EnterJoin_constraint(c *Join_constraintContext)
// EnterCompound_operator is called when entering the compound_operator production.
EnterCompound_operator(c *Compound_operatorContext)
// EnterUpdate_stmt is called when entering the update_stmt production.
EnterUpdate_stmt(c *Update_stmtContext)
// EnterAssignment_list is called when entering the assignment_list production.
EnterAssignment_list(c *Assignment_listContext)
// EnterAssignment is called when entering the assignment production.
EnterAssignment(c *AssignmentContext)
// EnterColumn_name_list is called when entering the column_name_list production.
EnterColumn_name_list(c *Column_name_listContext)
// EnterUpdate_stmt_limited is called when entering the update_stmt_limited production.
EnterUpdate_stmt_limited(c *Update_stmt_limitedContext)
// EnterQualified_table_name is called when entering the qualified_table_name production.
EnterQualified_table_name(c *Qualified_table_nameContext)
// EnterVacuum_stmt is called when entering the vacuum_stmt production.
EnterVacuum_stmt(c *Vacuum_stmtContext)
// EnterFilter_clause is called when entering the filter_clause production.
EnterFilter_clause(c *Filter_clauseContext)
// EnterWindow_defn is called when entering the window_defn production.
EnterWindow_defn(c *Window_defnContext)
// EnterOver_clause is called when entering the over_clause production.
EnterOver_clause(c *Over_clauseContext)
// EnterFrame_spec is called when entering the frame_spec production.
EnterFrame_spec(c *Frame_specContext)
// EnterFrame_clause is called when entering the frame_clause production.
EnterFrame_clause(c *Frame_clauseContext)
// EnterSimple_function_invocation is called when entering the simple_function_invocation production.
EnterSimple_function_invocation(c *Simple_function_invocationContext)
// EnterAggregate_function_invocation is called when entering the aggregate_function_invocation production.
EnterAggregate_function_invocation(c *Aggregate_function_invocationContext)
// EnterWindow_function_invocation is called when entering the window_function_invocation production.
EnterWindow_function_invocation(c *Window_function_invocationContext)
// EnterCommon_table_stmt is called when entering the common_table_stmt production.
EnterCommon_table_stmt(c *Common_table_stmtContext)
// EnterOrder_by_stmt is called when entering the order_by_stmt production.
EnterOrder_by_stmt(c *Order_by_stmtContext)
// EnterLimit_stmt is called when entering the limit_stmt production.
EnterLimit_stmt(c *Limit_stmtContext)
// EnterOrdering_term is called when entering the ordering_term production.
EnterOrdering_term(c *Ordering_termContext)
// EnterAsc_desc is called when entering the asc_desc production.
EnterAsc_desc(c *Asc_descContext)
// EnterFrame_left is called when entering the frame_left production.
EnterFrame_left(c *Frame_leftContext)
// EnterFrame_right is called when entering the frame_right production.
EnterFrame_right(c *Frame_rightContext)
// EnterFrame_single is called when entering the frame_single production.
EnterFrame_single(c *Frame_singleContext)
// EnterWindow_function is called when entering the window_function production.
EnterWindow_function(c *Window_functionContext)
// EnterOffset is called when entering the offset production.
EnterOffset(c *OffsetContext)
// EnterDefault_value is called when entering the default_value production.
EnterDefault_value(c *Default_valueContext)
// EnterPartition_by is called when entering the partition_by production.
EnterPartition_by(c *Partition_byContext)
// EnterOrder_by_expr is called when entering the order_by_expr production.
EnterOrder_by_expr(c *Order_by_exprContext)
// EnterOrder_by_expr_asc_desc is called when entering the order_by_expr_asc_desc production.
EnterOrder_by_expr_asc_desc(c *Order_by_expr_asc_descContext)
// EnterExpr_asc_desc is called when entering the expr_asc_desc production.
EnterExpr_asc_desc(c *Expr_asc_descContext)
// EnterInitial_select is called when entering the initial_select production.
EnterInitial_select(c *Initial_selectContext)
// EnterRecursive_select is called when entering the recursive_select production.
EnterRecursive_select(c *Recursive_selectContext)
// EnterUnary_operator is called when entering the unary_operator production.
EnterUnary_operator(c *Unary_operatorContext)
// EnterError_message is called when entering the error_message production.
EnterError_message(c *Error_messageContext)
// EnterModule_argument is called when entering the module_argument production.
EnterModule_argument(c *Module_argumentContext)
// EnterColumn_alias is called when entering the column_alias production.
EnterColumn_alias(c *Column_aliasContext)
// EnterKeyword is called when entering the keyword production.
EnterKeyword(c *KeywordContext)
// EnterName is called when entering the name production.
EnterName(c *NameContext)
// EnterFunction_name is called when entering the function_name production.
EnterFunction_name(c *Function_nameContext)
// EnterSchema_name is called when entering the schema_name production.
EnterSchema_name(c *Schema_nameContext)
// EnterTable_name is called when entering the table_name production.
EnterTable_name(c *Table_nameContext)
// EnterTable_or_index_name is called when entering the table_or_index_name production.
EnterTable_or_index_name(c *Table_or_index_nameContext)
// EnterColumn_name is called when entering the column_name production.
EnterColumn_name(c *Column_nameContext)
// EnterCollation_name is called when entering the collation_name production.
EnterCollation_name(c *Collation_nameContext)
// EnterForeign_table is called when entering the foreign_table production.
EnterForeign_table(c *Foreign_tableContext)
// EnterIndex_name is called when entering the index_name production.
EnterIndex_name(c *Index_nameContext)
// EnterTrigger_name is called when entering the trigger_name production.
EnterTrigger_name(c *Trigger_nameContext)
// EnterView_name is called when entering the view_name production.
EnterView_name(c *View_nameContext)
// EnterModule_name is called when entering the module_name production.
EnterModule_name(c *Module_nameContext)
// EnterPragma_name is called when entering the pragma_name production.
EnterPragma_name(c *Pragma_nameContext)
// EnterSavepoint_name is called when entering the savepoint_name production.
EnterSavepoint_name(c *Savepoint_nameContext)
// EnterTable_alias is called when entering the table_alias production.
EnterTable_alias(c *Table_aliasContext)
// EnterTransaction_name is called when entering the transaction_name production.
EnterTransaction_name(c *Transaction_nameContext)
// EnterWindow_name is called when entering the window_name production.
EnterWindow_name(c *Window_nameContext)
// EnterAlias is called when entering the alias production.
EnterAlias(c *AliasContext)
// EnterFilename is called when entering the filename production.
EnterFilename(c *FilenameContext)
// EnterBase_window_name is called when entering the base_window_name production.
EnterBase_window_name(c *Base_window_nameContext)
// EnterSimple_func is called when entering the simple_func production.
EnterSimple_func(c *Simple_funcContext)
// EnterAggregate_func is called when entering the aggregate_func production.
EnterAggregate_func(c *Aggregate_funcContext)
// EnterTable_function_name is called when entering the table_function_name production.
EnterTable_function_name(c *Table_function_nameContext)
// EnterAny_name is called when entering the any_name production.
EnterAny_name(c *Any_nameContext)
// ExitParse is called when exiting the parse production.
ExitParse(c *ParseContext)
// ExitSql_stmt_list is called when exiting the sql_stmt_list production.
ExitSql_stmt_list(c *Sql_stmt_listContext)
// ExitSql_stmt is called when exiting the sql_stmt production.
ExitSql_stmt(c *Sql_stmtContext)
// ExitAlter_table_stmt is called when exiting the alter_table_stmt production.
ExitAlter_table_stmt(c *Alter_table_stmtContext)
// ExitAnalyze_stmt is called when exiting the analyze_stmt production.
ExitAnalyze_stmt(c *Analyze_stmtContext)
// ExitAttach_stmt is called when exiting the attach_stmt production.
ExitAttach_stmt(c *Attach_stmtContext)
// ExitBegin_stmt is called when exiting the begin_stmt production.
ExitBegin_stmt(c *Begin_stmtContext)
// ExitCommit_stmt is called when exiting the commit_stmt production.
ExitCommit_stmt(c *Commit_stmtContext)
// ExitRollback_stmt is called when exiting the rollback_stmt production.
ExitRollback_stmt(c *Rollback_stmtContext)
// ExitSavepoint_stmt is called when exiting the savepoint_stmt production.
ExitSavepoint_stmt(c *Savepoint_stmtContext)
// ExitRelease_stmt is called when exiting the release_stmt production.
ExitRelease_stmt(c *Release_stmtContext)
// ExitCreate_index_stmt is called when exiting the create_index_stmt production.
ExitCreate_index_stmt(c *Create_index_stmtContext)
// ExitIndexed_column is called when exiting the indexed_column production.
ExitIndexed_column(c *Indexed_columnContext)
// ExitCreate_table_stmt is called when exiting the create_table_stmt production.
ExitCreate_table_stmt(c *Create_table_stmtContext)
// ExitColumn_def is called when exiting the column_def production.
ExitColumn_def(c *Column_defContext)
// ExitType_name is called when exiting the type_name production.
ExitType_name(c *Type_nameContext)
// ExitColumn_constraint is called when exiting the column_constraint production.
ExitColumn_constraint(c *Column_constraintContext)
// ExitSigned_number is called when exiting the signed_number production.
ExitSigned_number(c *Signed_numberContext)
// ExitTable_constraint is called when exiting the table_constraint production.
ExitTable_constraint(c *Table_constraintContext)
// ExitForeign_key_clause is called when exiting the foreign_key_clause production.
ExitForeign_key_clause(c *Foreign_key_clauseContext)
// ExitConflict_clause is called when exiting the conflict_clause production.
ExitConflict_clause(c *Conflict_clauseContext)
// ExitCreate_trigger_stmt is called when exiting the create_trigger_stmt production.
ExitCreate_trigger_stmt(c *Create_trigger_stmtContext)
// ExitCreate_view_stmt is called when exiting the create_view_stmt production.
ExitCreate_view_stmt(c *Create_view_stmtContext)
// ExitCreate_virtual_table_stmt is called when exiting the create_virtual_table_stmt production.
ExitCreate_virtual_table_stmt(c *Create_virtual_table_stmtContext)
// ExitWith_clause is called when exiting the with_clause production.
ExitWith_clause(c *With_clauseContext)
// ExitCte_table_name is called when exiting the cte_table_name production.
ExitCte_table_name(c *Cte_table_nameContext)
// ExitRecursive_cte is called when exiting the recursive_cte production.
ExitRecursive_cte(c *Recursive_cteContext)
// ExitCommon_table_expression is called when exiting the common_table_expression production.
ExitCommon_table_expression(c *Common_table_expressionContext)
// ExitDelete_stmt is called when exiting the delete_stmt production.
ExitDelete_stmt(c *Delete_stmtContext)
// ExitDelete_stmt_limited is called when exiting the delete_stmt_limited production.
ExitDelete_stmt_limited(c *Delete_stmt_limitedContext)
// ExitDetach_stmt is called when exiting the detach_stmt production.
ExitDetach_stmt(c *Detach_stmtContext)
// ExitDrop_stmt is called when exiting the drop_stmt production.
ExitDrop_stmt(c *Drop_stmtContext)
// ExitExpr is called when exiting the expr production.
ExitExpr(c *ExprContext)
// ExitRaise_function is called when exiting the raise_function production.
ExitRaise_function(c *Raise_functionContext)
// ExitLiteral_value is called when exiting the literal_value production.
ExitLiteral_value(c *Literal_valueContext)
// ExitInsert_stmt is called when exiting the insert_stmt production.
ExitInsert_stmt(c *Insert_stmtContext)
// ExitReturning_clause is called when exiting the returning_clause production.
ExitReturning_clause(c *Returning_clauseContext)
// ExitUpsert_clause is called when exiting the upsert_clause production.
ExitUpsert_clause(c *Upsert_clauseContext)
// ExitPragma_stmt is called when exiting the pragma_stmt production.
ExitPragma_stmt(c *Pragma_stmtContext)
// ExitPragma_value is called when exiting the pragma_value production.
ExitPragma_value(c *Pragma_valueContext)
// ExitReindex_stmt is called when exiting the reindex_stmt production.
ExitReindex_stmt(c *Reindex_stmtContext)
// ExitSelect_stmt is called when exiting the select_stmt production.
ExitSelect_stmt(c *Select_stmtContext)
// ExitJoin_clause is called when exiting the join_clause production.
ExitJoin_clause(c *Join_clauseContext)
// ExitSelect_core is called when exiting the select_core production.
ExitSelect_core(c *Select_coreContext)
// ExitFactored_select_stmt is called when exiting the factored_select_stmt production.
ExitFactored_select_stmt(c *Factored_select_stmtContext)
// ExitSimple_select_stmt is called when exiting the simple_select_stmt production.
ExitSimple_select_stmt(c *Simple_select_stmtContext)
// ExitCompound_select_stmt is called when exiting the compound_select_stmt production.
ExitCompound_select_stmt(c *Compound_select_stmtContext)
// ExitTable_or_subquery is called when exiting the table_or_subquery production.
ExitTable_or_subquery(c *Table_or_subqueryContext)
// ExitResult_column is called when exiting the result_column production.
ExitResult_column(c *Result_columnContext)
// ExitJoin_operator is called when exiting the join_operator production.
ExitJoin_operator(c *Join_operatorContext)
// ExitJoin_constraint is called when exiting the join_constraint production.
ExitJoin_constraint(c *Join_constraintContext)
// ExitCompound_operator is called when exiting the compound_operator production.
ExitCompound_operator(c *Compound_operatorContext)
// ExitUpdate_stmt is called when exiting the update_stmt production.
ExitUpdate_stmt(c *Update_stmtContext)
// ExitAssignment_list is called when exiting the assignment_list production.
ExitAssignment_list(c *Assignment_listContext)
// ExitAssignment is called when exiting the assignment production.
ExitAssignment(c *AssignmentContext)
// ExitColumn_name_list is called when exiting the column_name_list production.
ExitColumn_name_list(c *Column_name_listContext)
// ExitUpdate_stmt_limited is called when exiting the update_stmt_limited production.
ExitUpdate_stmt_limited(c *Update_stmt_limitedContext)
// ExitQualified_table_name is called when exiting the qualified_table_name production.
ExitQualified_table_name(c *Qualified_table_nameContext)
// ExitVacuum_stmt is called when exiting the vacuum_stmt production.
ExitVacuum_stmt(c *Vacuum_stmtContext)
// ExitFilter_clause is called when exiting the filter_clause production.
ExitFilter_clause(c *Filter_clauseContext)
// ExitWindow_defn is called when exiting the window_defn production.
ExitWindow_defn(c *Window_defnContext)
// ExitOver_clause is called when exiting the over_clause production.
ExitOver_clause(c *Over_clauseContext)
// ExitFrame_spec is called when exiting the frame_spec production.
ExitFrame_spec(c *Frame_specContext)
// ExitFrame_clause is called when exiting the frame_clause production.
ExitFrame_clause(c *Frame_clauseContext)
// ExitSimple_function_invocation is called when exiting the simple_function_invocation production.
ExitSimple_function_invocation(c *Simple_function_invocationContext)
// ExitAggregate_function_invocation is called when exiting the aggregate_function_invocation production.
ExitAggregate_function_invocation(c *Aggregate_function_invocationContext)
// ExitWindow_function_invocation is called when exiting the window_function_invocation production.
ExitWindow_function_invocation(c *Window_function_invocationContext)
// ExitCommon_table_stmt is called when exiting the common_table_stmt production.
ExitCommon_table_stmt(c *Common_table_stmtContext)
// ExitOrder_by_stmt is called when exiting the order_by_stmt production.
ExitOrder_by_stmt(c *Order_by_stmtContext)
// ExitLimit_stmt is called when exiting the limit_stmt production.
ExitLimit_stmt(c *Limit_stmtContext)
// ExitOrdering_term is called when exiting the ordering_term production.
ExitOrdering_term(c *Ordering_termContext)
// ExitAsc_desc is called when exiting the asc_desc production.
ExitAsc_desc(c *Asc_descContext)
// ExitFrame_left is called when exiting the frame_left production.
ExitFrame_left(c *Frame_leftContext)
// ExitFrame_right is called when exiting the frame_right production.
ExitFrame_right(c *Frame_rightContext)
// ExitFrame_single is called when exiting the frame_single production.
ExitFrame_single(c *Frame_singleContext)
// ExitWindow_function is called when exiting the window_function production.
ExitWindow_function(c *Window_functionContext)
// ExitOffset is called when exiting the offset production.
ExitOffset(c *OffsetContext)
// ExitDefault_value is called when exiting the default_value production.
ExitDefault_value(c *Default_valueContext)
// ExitPartition_by is called when exiting the partition_by production.
ExitPartition_by(c *Partition_byContext)
// ExitOrder_by_expr is called when exiting the order_by_expr production.
ExitOrder_by_expr(c *Order_by_exprContext)
// ExitOrder_by_expr_asc_desc is called when exiting the order_by_expr_asc_desc production.
ExitOrder_by_expr_asc_desc(c *Order_by_expr_asc_descContext)
// ExitExpr_asc_desc is called when exiting the expr_asc_desc production.
ExitExpr_asc_desc(c *Expr_asc_descContext)
// ExitInitial_select is called when exiting the initial_select production.
ExitInitial_select(c *Initial_selectContext)
// ExitRecursive_select is called when exiting the recursive_select production.
ExitRecursive_select(c *Recursive_selectContext)
// ExitUnary_operator is called when exiting the unary_operator production.
ExitUnary_operator(c *Unary_operatorContext)
// ExitError_message is called when exiting the error_message production.
ExitError_message(c *Error_messageContext)
// ExitModule_argument is called when exiting the module_argument production.
ExitModule_argument(c *Module_argumentContext)
// ExitColumn_alias is called when exiting the column_alias production.
ExitColumn_alias(c *Column_aliasContext)
// ExitKeyword is called when exiting the keyword production.
ExitKeyword(c *KeywordContext)
// ExitName is called when exiting the name production.
ExitName(c *NameContext)
// ExitFunction_name is called when exiting the function_name production.
ExitFunction_name(c *Function_nameContext)
// ExitSchema_name is called when exiting the schema_name production.
ExitSchema_name(c *Schema_nameContext)
// ExitTable_name is called when exiting the table_name production.
ExitTable_name(c *Table_nameContext)
// ExitTable_or_index_name is called when exiting the table_or_index_name production.
ExitTable_or_index_name(c *Table_or_index_nameContext)
// ExitColumn_name is called when exiting the column_name production.
ExitColumn_name(c *Column_nameContext)
// ExitCollation_name is called when exiting the collation_name production.
ExitCollation_name(c *Collation_nameContext)
// ExitForeign_table is called when exiting the foreign_table production.
ExitForeign_table(c *Foreign_tableContext)
// ExitIndex_name is called when exiting the index_name production.
ExitIndex_name(c *Index_nameContext)
// ExitTrigger_name is called when exiting the trigger_name production.
ExitTrigger_name(c *Trigger_nameContext)
// ExitView_name is called when exiting the view_name production.
ExitView_name(c *View_nameContext)
// ExitModule_name is called when exiting the module_name production.
ExitModule_name(c *Module_nameContext)
// ExitPragma_name is called when exiting the pragma_name production.
ExitPragma_name(c *Pragma_nameContext)
// ExitSavepoint_name is called when exiting the savepoint_name production.
ExitSavepoint_name(c *Savepoint_nameContext)
// ExitTable_alias is called when exiting the table_alias production.
ExitTable_alias(c *Table_aliasContext)
// ExitTransaction_name is called when exiting the transaction_name production.
ExitTransaction_name(c *Transaction_nameContext)
// ExitWindow_name is called when exiting the window_name production.
ExitWindow_name(c *Window_nameContext)
// ExitAlias is called when exiting the alias production.
ExitAlias(c *AliasContext)
// ExitFilename is called when exiting the filename production.
ExitFilename(c *FilenameContext)
// ExitBase_window_name is called when exiting the base_window_name production.
ExitBase_window_name(c *Base_window_nameContext)
// ExitSimple_func is called when exiting the simple_func production.
ExitSimple_func(c *Simple_funcContext)
// ExitAggregate_func is called when exiting the aggregate_func production.
ExitAggregate_func(c *Aggregate_funcContext)
// ExitTable_function_name is called when exiting the table_function_name production.
ExitTable_function_name(c *Table_function_nameContext)
// ExitAny_name is called when exiting the any_name production.
ExitAny_name(c *Any_nameContext)
}
================================================
FILE: cmd/atlas/internal/sqlparse/sqliteparse/parser_visitor.go
================================================
// Code generated from Parser.g4 by ANTLR 4.13.1. DO NOT EDIT.
package sqliteparse // Parser
import "github.com/antlr4-go/antlr/v4"
// A complete Visitor for a parse tree produced by Parser.
type ParserVisitor interface {
antlr.ParseTreeVisitor
// Visit a parse tree produced by Parser#parse.
VisitParse(ctx *ParseContext) interface{}
// Visit a parse tree produced by Parser#sql_stmt_list.
VisitSql_stmt_list(ctx *Sql_stmt_listContext) interface{}
// Visit a parse tree produced by Parser#sql_stmt.
VisitSql_stmt(ctx *Sql_stmtContext) interface{}
// Visit a parse tree produced by Parser#alter_table_stmt.
VisitAlter_table_stmt(ctx *Alter_table_stmtContext) interface{}
// Visit a parse tree produced by Parser#analyze_stmt.
VisitAnalyze_stmt(ctx *Analyze_stmtContext) interface{}
// Visit a parse tree produced by Parser#attach_stmt.
VisitAttach_stmt(ctx *Attach_stmtContext) interface{}
// Visit a parse tree produced by Parser#begin_stmt.
VisitBegin_stmt(ctx *Begin_stmtContext) interface{}
// Visit a parse tree produced by Parser#commit_stmt.
VisitCommit_stmt(ctx *Commit_stmtContext) interface{}
// Visit a parse tree produced by Parser#rollback_stmt.
VisitRollback_stmt(ctx *Rollback_stmtContext) interface{}
// Visit a parse tree produced by Parser#savepoint_stmt.
VisitSavepoint_stmt(ctx *Savepoint_stmtContext) interface{}
// Visit a parse tree produced by Parser#release_stmt.
VisitRelease_stmt(ctx *Release_stmtContext) interface{}
// Visit a parse tree produced by Parser#create_index_stmt.
VisitCreate_index_stmt(ctx *Create_index_stmtContext) interface{}
// Visit a parse tree produced by Parser#indexed_column.
VisitIndexed_column(ctx *Indexed_columnContext) interface{}
// Visit a parse tree produced by Parser#create_table_stmt.
VisitCreate_table_stmt(ctx *Create_table_stmtContext) interface{}
// Visit a parse tree produced by Parser#column_def.
VisitColumn_def(ctx *Column_defContext) interface{}
// Visit a parse tree produced by Parser#type_name.
VisitType_name(ctx *Type_nameContext) interface{}
// Visit a parse tree produced by Parser#column_constraint.
VisitColumn_constraint(ctx *Column_constraintContext) interface{}
// Visit a parse tree produced by Parser#signed_number.
VisitSigned_number(ctx *Signed_numberContext) interface{}
// Visit a parse tree produced by Parser#table_constraint.
VisitTable_constraint(ctx *Table_constraintContext) interface{}
// Visit a parse tree produced by Parser#foreign_key_clause.
VisitForeign_key_clause(ctx *Foreign_key_clauseContext) interface{}
// Visit a parse tree produced by Parser#conflict_clause.
VisitConflict_clause(ctx *Conflict_clauseContext) interface{}
// Visit a parse tree produced by Parser#create_trigger_stmt.
VisitCreate_trigger_stmt(ctx *Create_trigger_stmtContext) interface{}
// Visit a parse tree produced by Parser#create_view_stmt.
VisitCreate_view_stmt(ctx *Create_view_stmtContext) interface{}
// Visit a parse tree produced by Parser#create_virtual_table_stmt.
VisitCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) interface{}
// Visit a parse tree produced by Parser#with_clause.
VisitWith_clause(ctx *With_clauseContext) interface{}
// Visit a parse tree produced by Parser#cte_table_name.
VisitCte_table_name(ctx *Cte_table_nameContext) interface{}
// Visit a parse tree produced by Parser#recursive_cte.
VisitRecursive_cte(ctx *Recursive_cteContext) interface{}
// Visit a parse tree produced by Parser#common_table_expression.
VisitCommon_table_expression(ctx *Common_table_expressionContext) interface{}
// Visit a parse tree produced by Parser#delete_stmt.
VisitDelete_stmt(ctx *Delete_stmtContext) interface{}
// Visit a parse tree produced by Parser#delete_stmt_limited.
VisitDelete_stmt_limited(ctx *Delete_stmt_limitedContext) interface{}
// Visit a parse tree produced by Parser#detach_stmt.
VisitDetach_stmt(ctx *Detach_stmtContext) interface{}
// Visit a parse tree produced by Parser#drop_stmt.
VisitDrop_stmt(ctx *Drop_stmtContext) interface{}
// Visit a parse tree produced by Parser#expr.
VisitExpr(ctx *ExprContext) interface{}
// Visit a parse tree produced by Parser#raise_function.
VisitRaise_function(ctx *Raise_functionContext) interface{}
// Visit a parse tree produced by Parser#literal_value.
VisitLiteral_value(ctx *Literal_valueContext) interface{}
// Visit a parse tree produced by Parser#insert_stmt.
VisitInsert_stmt(ctx *Insert_stmtContext) interface{}
// Visit a parse tree produced by Parser#returning_clause.
VisitReturning_clause(ctx *Returning_clauseContext) interface{}
// Visit a parse tree produced by Parser#upsert_clause.
VisitUpsert_clause(ctx *Upsert_clauseContext) interface{}
// Visit a parse tree produced by Parser#pragma_stmt.
VisitPragma_stmt(ctx *Pragma_stmtContext) interface{}
// Visit a parse tree produced by Parser#pragma_value.
VisitPragma_value(ctx *Pragma_valueContext) interface{}
// Visit a parse tree produced by Parser#reindex_stmt.
VisitReindex_stmt(ctx *Reindex_stmtContext) interface{}
// Visit a parse tree produced by Parser#select_stmt.
VisitSelect_stmt(ctx *Select_stmtContext) interface{}
// Visit a parse tree produced by Parser#join_clause.
VisitJoin_clause(ctx *Join_clauseContext) interface{}
// Visit a parse tree produced by Parser#select_core.
VisitSelect_core(ctx *Select_coreContext) interface{}
// Visit a parse tree produced by Parser#factored_select_stmt.
VisitFactored_select_stmt(ctx *Factored_select_stmtContext) interface{}
// Visit a parse tree produced by Parser#simple_select_stmt.
VisitSimple_select_stmt(ctx *Simple_select_stmtContext) interface{}
// Visit a parse tree produced by Parser#compound_select_stmt.
VisitCompound_select_stmt(ctx *Compound_select_stmtContext) interface{}
// Visit a parse tree produced by Parser#table_or_subquery.
VisitTable_or_subquery(ctx *Table_or_subqueryContext) interface{}
// Visit a parse tree produced by Parser#result_column.
VisitResult_column(ctx *Result_columnContext) interface{}
// Visit a parse tree produced by Parser#join_operator.
VisitJoin_operator(ctx *Join_operatorContext) interface{}
// Visit a parse tree produced by Parser#join_constraint.
VisitJoin_constraint(ctx *Join_constraintContext) interface{}
// Visit a parse tree produced by Parser#compound_operator.
VisitCompound_operator(ctx *Compound_operatorContext) interface{}
// Visit a parse tree produced by Parser#update_stmt.
VisitUpdate_stmt(ctx *Update_stmtContext) interface{}
// Visit a parse tree produced by Parser#assignment_list.
VisitAssignment_list(ctx *Assignment_listContext) interface{}
// Visit a parse tree produced by Parser#assignment.
VisitAssignment(ctx *AssignmentContext) interface{}
// Visit a parse tree produced by Parser#column_name_list.
VisitColumn_name_list(ctx *Column_name_listContext) interface{}
// Visit a parse tree produced by Parser#update_stmt_limited.
VisitUpdate_stmt_limited(ctx *Update_stmt_limitedContext) interface{}
// Visit a parse tree produced by Parser#qualified_table_name.
VisitQualified_table_name(ctx *Qualified_table_nameContext) interface{}
// Visit a parse tree produced by Parser#vacuum_stmt.
VisitVacuum_stmt(ctx *Vacuum_stmtContext) interface{}
// Visit a parse tree produced by Parser#filter_clause.
VisitFilter_clause(ctx *Filter_clauseContext) interface{}
// Visit a parse tree produced by Parser#window_defn.
VisitWindow_defn(ctx *Window_defnContext) interface{}
// Visit a parse tree produced by Parser#over_clause.
VisitOver_clause(ctx *Over_clauseContext) interface{}
// Visit a parse tree produced by Parser#frame_spec.
VisitFrame_spec(ctx *Frame_specContext) interface{}
// Visit a parse tree produced by Parser#frame_clause.
VisitFrame_clause(ctx *Frame_clauseContext) interface{}
// Visit a parse tree produced by Parser#simple_function_invocation.
VisitSimple_function_invocation(ctx *Simple_function_invocationContext) interface{}
// Visit a parse tree produced by Parser#aggregate_function_invocation.
VisitAggregate_function_invocation(ctx *Aggregate_function_invocationContext) interface{}
// Visit a parse tree produced by Parser#window_function_invocation.
VisitWindow_function_invocation(ctx *Window_function_invocationContext) interface{}
// Visit a parse tree produced by Parser#common_table_stmt.
VisitCommon_table_stmt(ctx *Common_table_stmtContext) interface{}
// Visit a parse tree produced by Parser#order_by_stmt.
VisitOrder_by_stmt(ctx *Order_by_stmtContext) interface{}
// Visit a parse tree produced by Parser#limit_stmt.
VisitLimit_stmt(ctx *Limit_stmtContext) interface{}
// Visit a parse tree produced by Parser#ordering_term.
VisitOrdering_term(ctx *Ordering_termContext) interface{}
// Visit a parse tree produced by Parser#asc_desc.
VisitAsc_desc(ctx *Asc_descContext) interface{}
// Visit a parse tree produced by Parser#frame_left.
VisitFrame_left(ctx *Frame_leftContext) interface{}
// Visit a parse tree produced by Parser#frame_right.
VisitFrame_right(ctx *Frame_rightContext) interface{}
// Visit a parse tree produced by Parser#frame_single.
VisitFrame_single(ctx *Frame_singleContext) interface{}
// Visit a parse tree produced by Parser#window_function.
VisitWindow_function(ctx *Window_functionContext) interface{}
// Visit a parse tree produced by Parser#offset.
VisitOffset(ctx *OffsetContext) interface{}
// Visit a parse tree produced by Parser#default_value.
VisitDefault_value(ctx *Default_valueContext) interface{}
// Visit a parse tree produced by Parser#partition_by.
VisitPartition_by(ctx *Partition_byContext) interface{}
// Visit a parse tree produced by Parser#order_by_expr.
VisitOrder_by_expr(ctx *Order_by_exprContext) interface{}
// Visit a parse tree produced by Parser#order_by_expr_asc_desc.
VisitOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) interface{}
// Visit a parse tree produced by Parser#expr_asc_desc.
VisitExpr_asc_desc(ctx *Expr_asc_descContext) interface{}
// Visit a parse tree produced by Parser#initial_select.
VisitInitial_select(ctx *Initial_selectContext) interface{}
// Visit a parse tree produced by Parser#recursive_select.
VisitRecursive_select(ctx *Recursive_selectContext) interface{}
// Visit a parse tree produced by Parser#unary_operator.
VisitUnary_operator(ctx *Unary_operatorContext) interface{}
// Visit a parse tree produced by Parser#error_message.
VisitError_message(ctx *Error_messageContext) interface{}
// Visit a parse tree produced by Parser#module_argument.
VisitModule_argument(ctx *Module_argumentContext) interface{}
// Visit a parse tree produced by Parser#column_alias.
VisitColumn_alias(ctx *Column_aliasContext) interface{}
// Visit a parse tree produced by Parser#keyword.
VisitKeyword(ctx *KeywordContext) interface{}
// Visit a parse tree produced by Parser#name.
VisitName(ctx *NameContext) interface{}
// Visit a parse tree produced by Parser#function_name.
VisitFunction_name(ctx *Function_nameContext) interface{}
// Visit a parse tree produced by Parser#schema_name.
VisitSchema_name(ctx *Schema_nameContext) interface{}
// Visit a parse tree produced by Parser#table_name.
VisitTable_name(ctx *Table_nameContext) interface{}
// Visit a parse tree produced by Parser#table_or_index_name.
VisitTable_or_index_name(ctx *Table_or_index_nameContext) interface{}
// Visit a parse tree produced by Parser#column_name.
VisitColumn_name(ctx *Column_nameContext) interface{}
// Visit a parse tree produced by Parser#collation_name.
VisitCollation_name(ctx *Collation_nameContext) interface{}
// Visit a parse tree produced by Parser#foreign_table.
VisitForeign_table(ctx *Foreign_tableContext) interface{}
// Visit a parse tree produced by Parser#index_name.
VisitIndex_name(ctx *Index_nameContext) interface{}
// Visit a parse tree produced by Parser#trigger_name.
VisitTrigger_name(ctx *Trigger_nameContext) interface{}
// Visit a parse tree produced by Parser#view_name.
VisitView_name(ctx *View_nameContext) interface{}
// Visit a parse tree produced by Parser#module_name.
VisitModule_name(ctx *Module_nameContext) interface{}
// Visit a parse tree produced by Parser#pragma_name.
VisitPragma_name(ctx *Pragma_nameContext) interface{}
// Visit a parse tree produced by Parser#savepoint_name.
VisitSavepoint_name(ctx *Savepoint_nameContext) interface{}
// Visit a parse tree produced by Parser#table_alias.
VisitTable_alias(ctx *Table_aliasContext) interface{}
// Visit a parse tree produced by Parser#transaction_name.
VisitTransaction_name(ctx *Transaction_nameContext) interface{}
// Visit a parse tree produced by Parser#window_name.
VisitWindow_name(ctx *Window_nameContext) interface{}
// Visit a parse tree produced by Parser#alias.
VisitAlias(ctx *AliasContext) interface{}
// Visit a parse tree produced by Parser#filename.
VisitFilename(ctx *FilenameContext) interface{}
// Visit a parse tree produced by Parser#base_window_name.
VisitBase_window_name(ctx *Base_window_nameContext) interface{}
// Visit a parse tree produced by Parser#simple_func.
VisitSimple_func(ctx *Simple_funcContext) interface{}
// Visit a parse tree produced by Parser#aggregate_func.
VisitAggregate_func(ctx *Aggregate_funcContext) interface{}
// Visit a parse tree produced by Parser#table_function_name.
VisitTable_function_name(ctx *Table_function_nameContext) interface{}
// Visit a parse tree produced by Parser#any_name.
VisitAny_name(ctx *Any_nameContext) interface{}
}
================================================
FILE: cmd/atlas/internal/sqlparse/sqliteparse/sqliteparse_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package sqliteparse
import (
"errors"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
)
type FileParser struct{}
func (*FileParser) ColumnFilledBefore([]*migrate.Stmt, *schema.Table, *schema.Column, int) (bool, error) {
return false, errors.New("unimplemented")
}
func (*FileParser) CreateViewAfter([]*migrate.Stmt, string, string, int) (bool, error) {
return false, errors.New("unimplemented")
}
func (*FileParser) FixChange(_ migrate.Driver, _ string, changes schema.Changes) (schema.Changes, error) {
return changes, nil // Unimplemented.
}
================================================
FILE: cmd/atlas/internal/sqlparse/sqlparse.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package sqlparse
import (
"sync"
"ariga.io/atlas/cmd/atlas/internal/sqlparse/myparse"
"ariga.io/atlas/cmd/atlas/internal/sqlparse/pgparse"
"ariga.io/atlas/cmd/atlas/internal/sqlparse/sqliteparse"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/mysql"
"ariga.io/atlas/sql/postgres"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlite"
)
// A Parser represents an SQL file parser used to fix, search and enrich schema.Changes.
type Parser interface {
// FixChange fixes the changes according to the given statement.
FixChange(d migrate.Driver, stmt string, changes schema.Changes) (schema.Changes, error)
// ColumnFilledBefore checks if the column was filled with values before the given position
// in the file. For example:
//
// UPDATE SET =
// UPDATE SET = WHERE IS NULL
//
ColumnFilledBefore([]*migrate.Stmt, *schema.Table, *schema.Column, int) (bool, error)
// CreateViewAfter checks if a view was created after the position with the given name
// to a table. For example:
//
// ALTER TABLE `users` RENAME TO `Users`
// CREATE VIEW `users` AS SELECT * FROM `Users`
//
CreateViewAfter(stmts []*migrate.Stmt, old, new string, pos int) (bool, error)
}
// drivers specific fixers.
var drivers sync.Map
// Register a fixer with the given name.
func Register(name string, f Parser) {
drivers.Store(name, f)
}
// ParserFor returns a ChangesFixer for the given driver.
func ParserFor(name string) Parser {
f, ok := drivers.Load(name)
if ok {
return f.(Parser)
}
return nil
}
func init() {
Register(mysql.DriverName, &myparse.FileParser{})
Register(postgres.DriverName, &pgparse.Parser{})
Register(sqlite.DriverName, &sqliteparse.FileParser{})
}
================================================
FILE: cmd/atlas/main.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package main
import (
"bytes"
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
"ariga.io/atlas/cmd/atlas/internal/cmdapi"
"ariga.io/atlas/cmd/atlas/internal/cmdapi/vercheck"
"ariga.io/atlas/cmd/atlas/internal/cmdlog"
_ "ariga.io/atlas/cmd/atlas/internal/docker"
_ "ariga.io/atlas/sql/mysql"
_ "ariga.io/atlas/sql/mysql/mysqlcheck"
_ "ariga.io/atlas/sql/postgres"
_ "ariga.io/atlas/sql/postgres/postgrescheck"
_ "ariga.io/atlas/sql/sqlite"
_ "ariga.io/atlas/sql/sqlite/sqlitecheck"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
"github.com/mattn/go-isatty"
_ "github.com/mattn/go-sqlite3"
"github.com/spf13/cobra"
_ "github.com/tursodatabase/libsql-client-go/libsql"
"golang.org/x/mod/semver"
)
func main() {
cmdapi.Root.SetOut(os.Stdout)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
// On first signal seen, cancel the context. On the second signal, force stop immediately.
stop := make(chan os.Signal, 2)
defer close(stop)
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
defer signal.Stop(stop)
<-stop // wait for first interrupt
cancel() // cancel context to gracefully stop
fmt.Fprintln(cmdapi.Root.OutOrStdout(), "\ninterrupt received, wait for exit or ^C to terminate")
// Wait for the context to be canceled. Issuing a second interrupt will cause the process to force stop.
<-stop // will not block if no signal received due to main routine exiting
os.Exit(1)
}()
ctx, err := extendContext(ctx)
cobra.CheckErr(err)
ctx, done := initialize(ctx)
update := checkForUpdate(ctx)
err = cmdapi.Root.ExecuteContext(ctx)
if u := update(); u != "" {
_ = cmdlog.WarnOnce(os.Stderr, cmdlog.ColorCyan(u))
}
done(err)
if err != nil {
os.Exit(1)
}
}
const (
// envNoUpdate when enabled it cancels checking for update
envNoUpdate = "ATLAS_NO_UPDATE_NOTIFIER"
vercheckURL = "https://vercheck.ariga.io"
)
func noText() string { return "" }
func checkForUpdate(ctx context.Context) func() string {
version := cmdapi.Version()
// Users may skip update checking behavior.
if v := os.Getenv(envNoUpdate); v != "" {
return noText
}
// Skip if the current binary version isn't set (dev mode).
if !semver.IsValid(version) {
return noText
}
endpoint := vercheckEndpoint(ctx)
vc := vercheck.New(endpoint)
if isatty.IsTerminal(os.Stdout.Fd()) {
return bgCheck(ctx, version, vc)
}
return func() string {
msg, _ := runCheck(ctx, vc, version)
return msg
}
}
// bgCheck checks for version updates and security advisories for Atlas in the background.
func bgCheck(ctx context.Context, version string, vc *vercheck.VerChecker) func() string {
done := make(chan struct{})
var message string
go func() {
defer close(done)
msg, err := runCheck(ctx, vc, version)
if err != nil {
return
}
message = msg
}()
return func() string {
select {
case <-done:
case <-time.After(time.Millisecond * 500):
}
return message
}
}
func runCheck(ctx context.Context, vc *vercheck.VerChecker, version string) (string, error) {
payload, err := vc.Check(ctx, version)
if err != nil {
return "", err
}
var b bytes.Buffer
if err := vercheck.Notify.Execute(&b, payload); err != nil {
return "", err
}
return b.String(), nil
}
================================================
FILE: cmd/atlas/main_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package main
import (
"context"
"fmt"
"os"
"runtime"
"time"
"ariga.io/atlas/cmd/atlas/internal/cmdlog"
"ariga.io/atlas/cmd/atlas/internal/cmdstate"
)
func extendContext(ctx context.Context) (context.Context, error) {
return ctx, nil
}
func vercheckEndpoint(context.Context) string {
return vercheckURL
}
// initialize is a no-op for the OSS version.
func initialize(ctx context.Context) (context.Context, func(error)) {
return ctx, func(err error) {
if err == nil {
return
}
const errorsFileName = "community_error.json"
type prompt struct {
LastSuggested time.Time `json:"last_suggested"`
}
state := &cmdstate.File[prompt]{Name: errorsFileName}
prev, err := state.Read()
if err != nil || time.Since(prev.LastSuggested) < 24*time.Hour {
return
}
release := "curl -sSf https://atlasgo.sh | sh"
if runtime.GOOS == "windows" {
release = "https://release.ariga.io/atlas/atlas-windows-amd64-latest.exe"
}
if err := cmdlog.WarnOnce(os.Stderr, cmdlog.ColorCyan(fmt.Sprintf(`You're running the community build of Atlas, which may differ from the official version.
If this error persists, try installing the official version as a troubleshooting step:
%s
More installation options: https://atlasgo.io/docs#installation
`, release))); err == nil {
prev.LastSuggested = time.Now()
_ = state.Write(prev)
}
}
}
================================================
FILE: go.mod
================================================
module ariga.io/atlas
go 1.24.13
require (
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/bmatcuk/doublestar v1.3.4
github.com/go-openapi/inflect v0.19.0
github.com/hashicorp/hcl/v2 v2.13.0
github.com/mattn/go-sqlite3 v1.14.28
github.com/stretchr/testify v1.11.1
github.com/zclconf/go-cty v1.14.4
github.com/zclconf/go-cty-yaml v1.1.0
golang.org/x/mod v0.26.0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/agext/levenshtein v1.2.1 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/text v0.28.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)
================================================
FILE: go.sum
================================================
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
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/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc=
github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
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/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
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/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
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/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0=
github.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
================================================
FILE: internal/ci/ci_dialect.tmpl
================================================
# # # # # # # # # # # # # # # #
# CODE GENERATED - DO NOT EDIT
# # # # # # # # # # # # # # # #
name: CI - Dialect Tests{{ with $.Flavor }} - {{ . }} Edition{{ end }}
on:
workflow_call:
{{ .Concurrency }}
{{- if .GlobalEnv }}
env:
{{- end }}
{{- range .GlobalEnv }}
{{ .K }}: {{ .V }}
{{- end }}
jobs:
{{- range $.Jobs }}
integration-{{ .Version }}:
runs-on: {{ or .Runner $.Runner }}
{{- if .Image }}
services:
{{ .Version }}:
image: {{ .Image }}
{{- with .Credentials }}
credentials:
username: {{ print `${{ ` .Username ` }}` }}
password: {{ print `${{ ` .Password ` }}` }}
{{- end }}
{{- with .Env }}
env:
{{- range . }}
{{ . }}{{ end }}
{{- end }}
{{- with .Ports }}
ports:
{{- range . }}
- {{ . }}{{ end }}
{{- end }}
{{- with .Volumes }}
volumes:
{{- range . }}
- {{ . }}{{ end }}
{{- end }}
{{- with .Options }}
options: >-
{{- range . }}
{{ . }}{{ end }}
{{- end }}
{{- end }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
{{- with .Steps }}
{{- range . }}
- name: {{ .Name }}
{{- with .Run }}
run: |
{{- range $line := split . "\n" }}
{{ $line | trim }}
{{- end }}
{{- end }}
{{- with .Action }}
uses: {{ . }}
{{- end }}
{{- with .With }}
with:
{{- range . }}
{{ . }}{{ end }}
{{- end }}
{{- end }}
{{- end }}
- name: Run integration tests for {{ .Version }}
working-directory: internal/integration
run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race -count=2 -v -run="{{ .Regex }}" -version="{{ .Version }}" -timeout 15m ./...
{{- with .Env }}
env:
{{- range . }}
{{ . }}{{ end }}
{{- end }}
{{- end }}
================================================
FILE: internal/ci/ci_go.tmpl
================================================
# # # # # # # # # # # # # # # #
# CODE GENERATED - DO NOT EDIT
# # # # # # # # # # # # # # # #
name: CI - General{{ with $.Flavor }} - {{ . }} Edition{{ end }}
on:
pull_request:
paths-ignore:
- 'doc/**'
- 'ops/**'
push:
branches:
- master
paths-ignore:
- 'doc/**'
- 'ops/**'
{{ .Concurrency }}
{{- if .GlobalEnv }}
env:
{{- end }}
{{- range .GlobalEnv }}
{{ .K }}: {{ .V }}
{{- end }}
jobs:
lint:
runs-on: {{ $.Runner }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
{{- with .SharedSteps }}
{{- range . }}
- name: {{ .Name }}
uses: {{ .Action }}
{{- with .With }}
with:
{{- range . }}
{{ . }}{{ end }}
{{- end }}
{{- end }}
{{- end }}
- name: Run linters
uses: golangci/golangci-lint-action@v6
with:
args: --verbose
generate-cmp:
runs-on: {{ $.Runner }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
{{- with .SharedSteps }}
{{- range . }}
- name: {{ .Name }}
uses: {{ .Action }}
{{- with .With }}
with:
{{- range . }}
{{ . }}{{ end }}
{{- end }}
{{- end }}
{{- end }}
- name: Install stringer
run: go install golang.org/x/tools/cmd/stringer@latest
- name: run "go generate ./..."
run: go generate ./...
- name: go generate cmd/atlas
working-directory: cmd/atlas
run: go generate ./...
- name: Verify generated files are checked-in properly
run: |
status=$(git status --porcelain | grep -v "go.\(sum\|mod\)" | cat)
if [ -n "$status" ]; then
echo "you need to run 'go generate ./...' and commit the changes"
echo "$status"
exit 1
fi
unit:
runs-on: {{ $.Runner }}
strategy:
matrix:
go: {{ with $.GoVersions }}{{ . }}{{ end }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: {{ "${{ matrix.go }}" }}
{{- with .SharedSteps }}
{{- range . }}
- name: {{ .Name }}
uses: {{ .Action }}
{{- with .With }}
with:
{{- range . }}
{{ . }}{{ end }}
{{- end }}
{{- end }}
{{- end }}
- name: Run sql tests
run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race ./...
working-directory: sql
- name: Run schemahcl tests
run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race ./...
working-directory: schemahcl
cli:
runs-on: {{ $.Runner }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
{{- with .SharedSteps }}
{{- range . }}
- name: {{ .Name }}
uses: {{ .Action }}
{{- with .With }}
with:
{{- range . }}
{{ . }}{{ end }}
{{- end }}
{{- end }}
{{- end }}
- name: Run cli tests
run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race ./...
working-directory: cmd/atlas
integration:
runs-on: {{ $.Runner }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
{{- with .SharedSteps }}
{{- range . }}
- name: {{ .Name }}
uses: {{ .Action }}
{{- with .With }}
with:
{{- range . }}
{{ . }}{{ end }}
{{- end }}
{{- end }}
{{- end }}
- name: Run integration tests for HCL
working-directory: internal/integration/hclsqlspec
run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race -count=2 -v ./...
dialect-integration:
needs: [lint, generate-cmp, unit, cli, integration]
uses: ./.github/workflows/ci-dialect_{{ $.Suffix }}.yaml
secrets: inherit
================================================
FILE: internal/ci/ci_revisions.tmpl
================================================
# # # # # # # # # # # # # # # #
# CODE GENERATED - DO NOT EDIT
# # # # # # # # # # # # # # # #
name: CI - Revisions{{ with $.Flavor }} - {{ . }} Edition{{ end }}
on:
pull_request:
paths:
- 'cmd/atlas/internal/migrate/ent/**'
push:
branches:
- master
paths:
- 'cmd/atlas/internal/migrate/ent/**'
{{ .Concurrency }}
jobs:
revisions:
runs-on: {{ $.Runner }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version-file: cmd/atlas/go.mod
{{- with .SharedSteps }}
{{- range . }}
- name: {{ .Name }}
uses: {{ .Action }}
{{- with .With }}
with:
{{- range . }}
{{ . }}{{ end }}
{{- end }}
{{- end }}
{{- end }}
- name: Checkout origin/master
run: git checkout origin/master
- name: Create revisions from master
run: go run {{ with $.Tags }}-tags={{ . }} {{ end }}. migrate apply --dir file://internal/cmdapi/testdata/sqlite --url sqlite://db?_fk=1
working-directory: cmd/atlas
- name: Checkout previous HEAD
run: git checkout -
- name: Migrate revisions table to HEAD
run: go run {{ with $.Tags }}-tags={{ . }} {{ end }}. migrate apply --dir file://internal/cmdapi/testdata/sqlite --url sqlite://db?_fk=1
working-directory: cmd/atlas
================================================
FILE: internal/ci/cockroach/Dockerfile.tmpl
================================================
FROM cockroachdb/cockroach:{{ .Version}}
EXPOSE 8080
EXPOSE 26257
ENTRYPOINT ["/cockroach/cockroach", "start-single-node", "--insecure"]
================================================
FILE: internal/ci/cockroach/main.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package main
import (
_ "embed"
"fmt"
"os"
"text/template"
)
type params struct {
Version string
}
//go:embed Dockerfile.tmpl
var dockerTmpl string
func main() {
if len(os.Args) < 2 {
fmt.Println("please supply version as argument e.g. 'v22.1.0'")
os.Exit(1)
}
p := params{
Version: os.Args[1],
}
t, err := template.New("docker").Parse(dockerTmpl)
if err != nil {
panic(err)
}
err = t.Execute(os.Stdout, p)
if err != nil {
panic(err)
}
}
================================================
FILE: internal/ci/jobs_oss.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build !ent
package main
//go:generate go run . -flavor Community -suffix oss
func init() {
data.GoVersions = goVersions{"1.22"}
data.GlobalEnv = []struct{ K, V string }{
{K: "ATLAS_NO_UPGRADE_SUGGESTIONS", V: "1"},
}
data.Jobs = append(jobs,
Job{
Version: "tidb5",
Image: "pingcap/tidb:v5.4.0",
Regex: "TiDB",
Ports: []string{"4309:4000"},
},
Job{
Version: "tidb6",
Image: "pingcap/tidb:v6.0.0",
Regex: "TiDB",
Ports: []string{"4310:4000"},
},
Job{
Version: "cockroach",
Image: "ghcr.io/ariga/cockroachdb-single-node:v21.2.11",
Regex: "Cockroach",
Ports: []string{"26257:26257"},
},
)
}
================================================
FILE: internal/ci/main.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package main
import (
"bytes"
"embed"
_ "embed"
"flag"
"fmt"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"text/template"
)
type (
// Step defines a step to run.
Step struct {
Name string
Action string
Run string
With []string
}
// Credentials is used to pull images from a private registry.
Credentials struct {
Username string
Password string
}
// Job defines an integration job to run.
Job struct {
Runner string // runner to use
Version string // version to test (passed to go test as flag which database dialect/version)
Image string // name of service
Credentials *Credentials // credentials to pull the image
Regex string // run regex
Env []string // env of service
Ports []string // port mappings
Volumes []string // volume mappings
Options []string // other options
Steps []Step // extra steps to run
}
)
var (
//go:embed *.tmpl
tplFS embed.FS
tpl = template.Must(template.New("").
Funcs(template.FuncMap{
"split": strings.Split,
"trim": strings.TrimSpace,
}).
ParseFS(tplFS, "*.tmpl"))
mysqlOptions = []string{
`--health-cmd "mysqladmin ping -ppass"`,
`--health-interval 10s`,
`--health-start-period 10s`,
`--health-timeout 5s`,
`--health-retries 10`,
}
mysqlEnv = []string{
"MYSQL_DATABASE: test",
"MYSQL_ROOT_PASSWORD: pass",
}
pgOptions = []string{
"--health-cmd pg_isready",
"--health-interval 10s",
"--health-timeout 5s",
"--health-retries 5",
}
pgEnv = []string{
"POSTGRES_DB: test",
"POSTGRES_PASSWORD: pass",
}
jobs = []Job{
{
Version: "mysql56",
Image: "mysql:5.6.35",
Regex: "MySQL",
Env: mysqlEnv,
Ports: []string{"3306:3306"},
Options: mysqlOptions,
},
{
Version: "mysql57",
Image: "mysql:5.7.26",
Regex: "MySQL",
Env: mysqlEnv,
Ports: []string{"3307:3306"},
Options: mysqlOptions,
},
{
Version: "mysql8",
Image: "mysql:8",
Regex: "MySQL",
Env: mysqlEnv,
Ports: []string{"3308:3306"},
Options: mysqlOptions,
},
{
Version: "maria107",
Image: "mariadb:10.7",
Regex: "MySQL",
Env: mysqlEnv,
Ports: []string{"4306:3306"},
Options: mysqlOptions,
},
{
Version: "maria102",
Image: "mariadb:10.2.32",
Regex: "MySQL",
Env: mysqlEnv,
Ports: []string{"4307:3306"},
Options: mysqlOptions,
},
{
Version: "maria103",
Image: "mariadb:10.3.13",
Regex: "MySQL",
Env: mysqlEnv,
Ports: []string{"4308:3306"},
Options: mysqlOptions,
},
{
Version: "postgres-ext-postgis",
Image: "postgis/postgis:latest",
Regex: "Postgres",
Env: pgEnv,
Ports: []string{"5429:5432"},
Options: pgOptions,
},
{
Version: "postgres10",
Image: "postgres:10",
Regex: "Postgres",
Env: pgEnv,
Ports: []string{"5430:5432"},
Options: pgOptions,
},
{
Version: "postgres11",
Image: "postgres:11",
Regex: "Postgres",
Env: pgEnv,
Ports: []string{"5431:5432"},
Options: pgOptions,
},
{
Version: "postgres12",
Image: "postgres:12.3",
Regex: "Postgres",
Env: pgEnv,
Ports: []string{"5432:5432"},
Options: pgOptions,
},
{
Version: "postgres13",
Image: "postgres:13.1",
Regex: "Postgres",
Env: pgEnv,
Ports: []string{"5433:5432"},
Options: pgOptions,
},
{
Version: "postgres14",
Image: "postgres:14",
Regex: "Postgres",
Env: pgEnv,
Ports: []string{"5434:5432"},
Options: pgOptions,
},
{
Version: "postgres15",
Image: "postgres:15",
Regex: "Postgres",
Env: pgEnv,
Ports: []string{"5435:5432"},
Options: pgOptions,
},
{
Version: "sqlite",
Regex: "SQLite.*",
},
}
)
type (
goVersions []string
concurrency struct {
group string
cancel bool
}
)
var data = struct {
Jobs []Job
Flavor, Tags, Runner, Suffix string
GoVersions goVersions
Concurrency concurrency
SharedSteps []Step
GlobalEnv []struct{ K, V string }
}{
Concurrency: concurrency{
group: "${{ github.workflow }}-${{ github.head_ref || github.run_id }}",
cancel: true,
},
}
func main() {
flag.StringVar(&data.Flavor, "flavor", "", "")
flag.StringVar(&data.Tags, "tags", "", "")
flag.StringVar(&data.Runner, "runner", "ubuntu-latest", "")
flag.StringVar(&data.Suffix, "suffix", "", "")
flag.Parse()
for _, n := range []string{"dialect", "go", "revisions"} {
var (
buf bytes.Buffer
g = data.Concurrency.group
)
if n == "dialect" {
// Dialect jobs are running after go jobs, putting them in the same concurrency group crates deadlock.
data.Concurrency.group = fmt.Sprintf("%s-dialect", g)
}
if err := tpl.ExecuteTemplate(&buf, fmt.Sprintf("ci_%s.tmpl", n), data); err != nil {
log.Fatalln(err)
}
data.Concurrency.group = g
err := os.WriteFile(filepath.Clean(fmt.Sprintf("../../.github/workflows/ci-%s_%s.yaml", n, data.Suffix)), buf.Bytes(), 0600)
if err != nil {
log.Fatalln(err)
}
}
}
func (v goVersions) String() (s string) {
for i := range v {
v[i] = strconv.Quote(v[i])
}
return fmt.Sprintf("[ %s ]", strings.Join(v, ", "))
}
func (c concurrency) String() (s string) {
return fmt.Sprintf("concurrency:\n group: %s\n cancel-in-progress: %t", c.group, c.cancel)
}
================================================
FILE: internal/integration/README.md
================================================
### This directory contains all integration tests for Atlas.
The provided `docker-compose.yaml` file contains images for each database the integration tests are run on. You can
start them by calling:
```shell
docker-compose --project-name atlas-integration up -d
```
The whole integration suite is then run by executing within this directory:
```shell
go test ./...
```
#### Selectively running tests
Running all integration tests (and keeping all database containers up all the time) consumes time and resources (and
power). You can execute only some of the tests by using the `-run` and `-dialect` flags:
The below examples don't require for you to have all docker containers running, instead only the ones used in the tests
have to be up.
Consider the following test in `mysql_test.go`:
```go
func TestMySQL_Executor(t *testing.T) {
myRun(t, func(t *myTest) {
testExecutor(t)
})
}
```
If you'd wanted to run that test only for mysql56, simply pass its full name into the `-run` flag:
```shell
# Run TestMySQL_Executor for all mysql versions
go test -run='MySQL_Executor' ./...
# Run TestMySQL_Executor for mysql 5.6 only
go test -run='MySQL_Executor/mysql56' ./...
```
If you'd like to run the above for Postgres 10, change the name respectively:
```shell
# Run TestPostgres_Executor for all postgres versions
go test -run='Postgres_Executor' ./...
# Run TestPostgres_Executor for postgres 10 only
go test -run='Postgres_Executor/postgres10' ./...
```
If you want to run all tests for one specific dialect, like only TiDB 5, you can use the `-dialect` flag:
```shell
go test -run='TiDB' -dialect='tidb5' ./...
```
================================================
FILE: internal/integration/cockroach_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package integration
import (
"context"
"database/sql"
"fmt"
"log"
"strings"
"sync"
"testing"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/postgres"
"ariga.io/atlas/sql/schema"
_ "github.com/lib/pq"
"github.com/stretchr/testify/require"
)
type crdbTest struct {
*testing.T
db *sql.DB
drv migrate.Driver
rrw migrate.RevisionReadWriter
version string
port int
once sync.Once
}
var crdbTests = map[string]*crdbTest{
"cockroach": {port: 26257},
}
func crdbRun(t *testing.T, fn func(*crdbTest)) {
for version, tt := range crdbTests {
if flagVersion == "" || flagVersion == version {
t.Run(version, func(t *testing.T) {
tt.once.Do(func() {
var err error
tt.version = version
tt.rrw = &rrw{}
tt.db, err = sql.Open("postgres", fmt.Sprintf("host=localhost port=%d user=root dbname=defaultdb password=pass sslmode=disable", tt.port))
if err != nil {
log.Fatalln(err)
}
dbs = append(dbs, tt.db) // close connection after all tests have been run
tt.drv, err = postgres.Open(tt.db)
if err != nil {
log.Fatalln(err)
}
})
tt := &crdbTest{T: t, db: tt.db, drv: tt.drv, version: version, port: tt.port, rrw: tt.rrw}
fn(tt)
})
}
}
}
func TestCockroach_Executor(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
testExecutor(t)
})
}
func TestCockroach_AddDropTable(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
testAddDrop(t)
})
}
func TestCockroach_Relation(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
testRelation(t)
})
}
func TestCockroach_AddIndexedColumns(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
s := &schema.Schema{
Name: "public",
}
usersT := &schema.Table{
Name: "users",
Schema: s,
Columns: []*schema.Column{{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}, Attrs: []schema.Attr{&postgres.Identity{}}}},
}
usersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
usersT.Columns = append(usersT.Columns, &schema.Column{
Name: "a",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.Literal{V: "10"},
}, &schema.Column{
Name: "b",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.Literal{V: "10"},
}, &schema.Column{
Name: "c",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.Literal{V: "10"},
})
parts := usersT.Columns[len(usersT.Columns)-3:]
usersT.Indexes = append(usersT.Indexes, &schema.Index{
Unique: true,
Name: "a_b_c_unique",
Parts: []*schema.IndexPart{{C: parts[0]}, {C: parts[1]}, {C: parts[2]}},
})
changes := t.diff(t.loadUsers(), usersT)
require.NotEmpty(t, changes, "usersT contains 3 new columns and 1 new index")
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// Dropping a column involves in a multi-column
// index causes the index to be dropped as well.
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
changes = t.diff(t.loadUsers(), usersT)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, t.loadUsers())
usersT = t.loadUsers()
_, ok := usersT.Index("a_b_c_unique")
require.False(t, ok)
})
}
func TestCockroach_AddColumns(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
usersT := t.users()
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
usersT.Columns = append(
usersT.Columns,
&schema.Column{Name: "a", Type: &schema.ColumnType{Type: &schema.BinaryType{T: "bytea"}}},
&schema.Column{Name: "b", Type: &schema.ColumnType{Type: &schema.FloatType{T: "double precision", Precision: 10}}, Default: &schema.Literal{V: "10.1"}},
&schema.Column{Name: "c", Type: &schema.ColumnType{Type: &schema.StringType{T: "character"}}, Default: &schema.Literal{V: "'y'"}},
&schema.Column{Name: "d", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 10, Scale: 2}}, Default: &schema.Literal{V: "0.99"}},
&schema.Column{Name: "e", Type: &schema.ColumnType{Type: &schema.JSONType{T: "json"}}, Default: &schema.Literal{V: "'{}'"}},
&schema.Column{Name: "f", Type: &schema.ColumnType{Type: &schema.JSONType{T: "jsonb"}}, Default: &schema.Literal{V: "'1'"}},
&schema.Column{Name: "g", Type: &schema.ColumnType{Type: &schema.FloatType{T: "float", Precision: 10}}, Default: &schema.Literal{V: "'1'"}},
&schema.Column{Name: "h", Type: &schema.ColumnType{Type: &schema.FloatType{T: "float", Precision: 30}}, Default: &schema.Literal{V: "'1'"}},
&schema.Column{Name: "i", Type: &schema.ColumnType{Type: &schema.FloatType{T: "float", Precision: 53}}, Default: &schema.Literal{V: "1"}},
&schema.Column{Name: "j", Type: &schema.ColumnType{Type: &postgres.SerialType{T: "serial"}}},
&schema.Column{Name: "m", Type: &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}, Null: true}, Default: &schema.Literal{V: "false"}},
&schema.Column{Name: "n", Type: &schema.ColumnType{Type: &schema.SpatialType{T: "geometry"}, Null: true}, Default: &schema.Literal{V: "'POINT(1 2)'"}},
&schema.Column{Name: "o", Type: &schema.ColumnType{Type: &schema.SpatialType{T: "geometry"}, Null: true}, Default: &schema.Literal{V: "'LINESTRING(0 0, 1440 900)'"}},
&schema.Column{Name: "q", Type: &schema.ColumnType{Type: &postgres.ArrayType{Type: &schema.StringType{T: "text"}, T: "text[]"}, Null: true}, Default: &schema.Literal{V: "'{}'"}},
)
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 14)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
}
func TestCockroach_ColumnInt(t *testing.T) {
ctx := context.Background()
run := func(t *testing.T, change func(*schema.Column)) {
crdbRun(t, func(t *crdbTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}}}},
}
err := t.drv.ApplyChanges(ctx, []schema.Change{&schema.AddTable{T: usersT}})
require.NoError(t, err)
t.dropTables(usersT.Name)
change(usersT.Columns[0])
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
}
t.Run("ChangeNull", func(t *testing.T) {
run(t, func(c *schema.Column) {
c.Type.Null = true
})
})
t.Run("ChangeDefault", func(t *testing.T) {
run(t, func(c *schema.Column) {
c.Default = &schema.RawExpr{X: "0"}
})
})
}
func TestCockroach_ColumnArray(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
usersT := t.users()
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
// Add column.
usersT.Columns = append(
usersT.Columns,
&schema.Column{Name: "a", Type: &schema.ColumnType{Raw: "bigint[]", Type: &postgres.ArrayType{Type: &schema.IntegerType{T: "bigint"}, T: "bigint[]"}}, Default: &schema.Literal{V: "'{1}'"}},
)
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// Check default.
usersT.Columns[2].Default = &schema.RawExpr{X: "ARRAY[1]"}
ensureNoChange(t, usersT)
// Change default.
usersT.Columns[2].Default = &schema.RawExpr{X: "ARRAY[1,2]"}
changes = t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
}
func TestCockroach_Enums(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
ctx := context.Background()
usersT := &schema.Table{
Name: "users",
Schema: t.realm().Schemas[0],
Columns: []*schema.Column{
{Name: "state", Type: &schema.ColumnType{Type: &schema.EnumType{T: "state", Values: []string{"on", "off"}}}},
},
}
t.Cleanup(func() {
_, err := t.drv.ExecContext(ctx, "DROP TYPE IF EXISTS state, day")
require.NoError(t, err)
})
// Create table with an enum column.
err := t.drv.ApplyChanges(ctx, []schema.Change{
&schema.AddObject{O: &schema.EnumType{T: "state", Values: []string{"on", "off"}, Schema: usersT.Schema}},
&schema.AddTable{T: usersT},
})
require.NoError(t, err, "create a new table with an enum column")
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
// Add another enum column.
usersT.Columns = append(
usersT.Columns,
&schema.Column{Name: "day", Type: &schema.ColumnType{Type: &schema.EnumType{T: "day", Values: []string{"sunday", "monday"}}}},
)
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
err = t.drv.ApplyChanges(ctx, []schema.Change{
&schema.AddObject{O: &schema.EnumType{T: "day", Values: []string{"sunday", "monday"}, Schema: usersT.Schema}},
&schema.ModifyTable{T: usersT, Changes: changes},
})
require.NoError(t, err, "add a new enum column to existing table")
ensureNoChange(t, usersT)
})
}
func TestCockroach_HCL(t *testing.T) {
full := `
schema "public" {
}
table "users" {
schema = schema.public
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
table "posts" {
schema = schema.public
column "id" {
type = int
}
column "tags" {
type = sql("text[]")
}
column "author_id" {
type = int
}
foreign_key "author" {
columns = [
table.posts.column.author_id,
]
ref_columns = [
table.users.column.id,
]
}
primary_key {
columns = [table.users.column.id]
}
}
`
empty := `
schema "public" {
}
`
crdbRun(t, func(t *crdbTest) {
testHCLIntegration(t, full, empty)
})
}
func TestCockroach_HCL_Realm(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
t.dropSchemas("second")
realm := t.loadRealm()
hcl, err := postgres.MarshalHCL(realm)
require.NoError(t, err)
wa := string(hcl) + `
schema "second" {
}
`
t.applyRealmHcl(wa)
realm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{})
require.NoError(t, err)
_, ok := realm.Schema("public")
require.True(t, ok)
_, ok = realm.Schema("second")
require.True(t, ok)
})
}
func TestCockroach_CLI(t *testing.T) {
h := `
schema "public" {
}
table "users" {
schema = schema.public
column "id" {
type = bigint
}
primary_key {
columns = [table.users.column.id]
}
}`
t.Run("SchemaInspect", func(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
testCLISchemaInspect(t, h, t.url(""), postgres.EvalHCL, "-s", "public")
})
})
t.Run("SchemaApply", func(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
testCLISchemaApply(t, h, t.url(""), "-s", "public")
})
})
t.Run("SchemaApplyDryRun", func(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
testCLISchemaApplyDry(t, h, t.url(""))
})
})
t.Run("SchemaApplyWithVars", func(t *testing.T) {
h := `
variable "tenant" {
type = string
}
schema "tenant" {
name = var.tenant
}
table "users" {
schema = schema.tenant
column "id" {
type = int
}
}
`
crdbRun(t, func(t *crdbTest) {
testCLISchemaApply(t, h, t.url(""), "--var", "tenant=public", "-s", "public")
})
})
t.Run("SchemaDiffRun", func(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
testCLISchemaDiff(t, t.url(""))
})
})
t.Run("SchemaApplyAutoApprove", func(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
testCLISchemaApplyAutoApprove(t, h, t.url(""), "-s", "public")
})
})
}
func TestCockroach_CLI_MultiSchema(t *testing.T) {
h := `
schema "public" {
}
table "users" {
schema = schema.public
column "id" {
type = bigint
}
primary_key {
columns = [table.users.column.id]
}
}
schema "test2" {
}
table "users" {
schema = schema.test2
column "id" {
type = bigint
}
primary_key {
columns = [table.users.column.id]
}
}`
t.Run("SchemaInspect", func(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
t.dropSchemas("test2")
t.dropTables("users")
testCLIMultiSchemaInspect(t, h, t.url(""), []string{"public", "test2"}, postgres.EvalHCL)
})
})
t.Run("SchemaApply", func(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
t.dropSchemas("test2")
t.dropTables("users")
testCLIMultiSchemaApply(t, h, t.url(""), []string{"public", "test2"}, postgres.EvalHCL)
})
})
}
func TestCockroach_DefaultsHCL(t *testing.T) {
n := "atlas_defaults"
crdbRun(t, func(t *crdbTest) {
ddl := `
create table atlas_defaults
(
string varchar(255) default 'hello_world',
quoted varchar(100) default 'never say "never"',
tBit bit(10) default B'10101',
ts timestamp default CURRENT_TIMESTAMP,
tstz timestamp with time zone default CURRENT_TIMESTAMP,
number int default 42
)
`
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
spec, err := postgres.MarshalHCL(realm.Schemas[0])
require.NoError(t, err)
var s schema.Schema
err = postgres.EvalHCLBytes(spec, &s, nil)
require.NoError(t, err)
t.dropTables(n)
t.applyHcl(string(spec))
ensureNoChange(t, realm.Schemas[0].Tables[0])
})
}
func TestCockroach_Sanity(t *testing.T) {
n := "atlas_types_sanity"
ddl := `
create table atlas_types_sanity
(
"tBit" bit(10) default B'100' null,
"tBitVar" bit varying(10) default B'100' null,
"tBoolean" boolean default false not null,
"tBool" bool default false not null,
"tBytea" bytea default E'\\001' not null,
"tCharacter" character(10) default 'atlas' null,
"tChar" char(10) default 'atlas' null,
"tCharVar" character varying(10) default 'atlas' null,
"tVarChar" varchar(10) default 'atlas' null,
"tText" text default 'atlas' null,
"tSmallInt" smallint default '10' null,
"tInteger" integer default '10' null,
"tBigInt" bigint default '10' null,
"tInt" int default '10' null,
"tInt2" int2 default '10' null,
"tInt4" int4 default '10' null,
"tInt8" int8 default '10' null,
"tInet" inet default '127.0.0.1' null,
"tGeometry" geometry default null,
"tDate" date default current_date null,
"tTime" time default current_time null,
"tTimeWTZ" time with time zone default current_time null,
"tTimeWOTZ" time without time zone default current_time null,
"tTimestamp" timestamp default now() null,
"tTimestampTZ" timestamptz default now() null,
"tTimestampWTZ" timestamp with time zone default now() null,
"tTimestampWOTZ" timestamp without time zone default now() null,
"tTimestampPrec" timestamp(4) default now() null,
"tDouble" double precision default 0 null,
"tReal" real default 0 null,
"tFloat8" float8 default 0 null,
"tFloat4" float4 default 0 null,
"tNumeric" numeric default 0 null,
"tDecimal" decimal default 0 null,
"tSmallSerial" smallserial ,
"tSerial" serial ,
"tBigSerial" bigserial ,
"tSerial2" serial2 ,
"tSerial4" serial4 ,
"tSerial8" serial8 ,
"tArray" text[10] default '{}' null,
"tJSON" json default '{"key":"value"}' null,
"tJSONB" jsonb default '{"key":"value"}' null,
"tUUID" uuid default 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11' null,
"tInterval" interval default '4 hours' null
);
`
crdbRun(t, func(t *crdbTest) {
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
require.Len(t, realm.Schemas, 1)
ts, ok := realm.Schemas[0].Table(n)
require.True(t, ok)
expected := schema.Table{
Name: n,
Schema: realm.Schemas[0],
Columns: []*schema.Column{
{
Name: "tBit",
Type: &schema.ColumnType{Type: &postgres.BitType{T: "bit", Len: 10}, Raw: "bit", Null: true},
Default: &schema.RawExpr{X: "B'100'"},
},
{
Name: "tBitVar",
Type: &schema.ColumnType{Type: &postgres.BitType{T: "bit varying", Len: 10}, Raw: "bit varying", Null: true},
Default: &schema.RawExpr{X: "B'100'"},
},
{
Name: "tBoolean",
Type: &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}, Raw: "boolean", Null: false},
Default: &schema.Literal{V: "false"},
},
{
Name: "tBool",
Type: &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}, Raw: "boolean", Null: false},
Default: &schema.Literal{V: "false"},
},
{
Name: "tBytea",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "bytea"}, Raw: "bytea", Null: false},
Default: &schema.RawExpr{X: "'\\x01':::BYTES"},
},
{
Name: "tCharacter",
Type: &schema.ColumnType{Type: &schema.StringType{T: "character", Size: 10}, Raw: "character", Null: true},
Default: &schema.RawExpr{X: "'atlas':::STRING"},
},
{
Name: "tChar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "character", Size: 10}, Raw: "character", Null: true},
Default: &schema.RawExpr{X: "'atlas':::STRING"},
},
{
Name: "tCharVar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "character varying", Size: 10}, Raw: "character varying", Null: true},
Default: &schema.RawExpr{X: "'atlas':::STRING"},
},
{
Name: "tVarChar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "character varying", Size: 10}, Raw: "character varying", Null: true},
Default: &schema.RawExpr{X: "'atlas':::STRING"},
},
{
Name: "tText",
Type: &schema.ColumnType{Type: &schema.StringType{T: "text"}, Raw: "text", Null: true},
Default: &schema.RawExpr{X: "'atlas':::STRING"},
},
{
Name: "tSmallInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "smallint"}, Raw: "smallint", Null: true},
Default: &schema.RawExpr{X: "10:::INT8"},
},
{
Name: "tInteger",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Raw: "bigint", Null: true},
Default: &schema.RawExpr{X: "10:::INT8"},
},
{
Name: "tBigInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Raw: "bigint", Null: true},
Default: &schema.RawExpr{X: "10:::INT8"},
},
{
Name: "tInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Raw: "bigint", Null: true},
Default: &schema.RawExpr{X: "10:::INT8"},
},
{
Name: "tInt2",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "smallint"}, Raw: "smallint", Null: true},
Default: &schema.RawExpr{X: "10:::INT8"},
},
{
Name: "tInt4",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Raw: "integer", Null: true},
Default: &schema.RawExpr{X: "10:::INT8"},
},
{
Name: "tInt8",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Raw: "bigint", Null: true},
Default: &schema.RawExpr{X: "10:::INT8"},
},
{
Name: "tInet",
Type: &schema.ColumnType{Type: &postgres.NetworkType{T: "inet"}, Raw: "inet", Null: true},
Default: &schema.RawExpr{X: "'127.0.0.1':::INET"},
},
{
Name: "tGeometry",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "geometry"}, Raw: "geometry", Null: true},
},
{
Name: "tDate",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "date"}, Raw: "date", Null: true},
Default: &schema.RawExpr{X: "current_date()"},
},
{
Name: "tTime",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "time without time zone", Precision: intp(6)}, Raw: "time without time zone", Null: true},
Default: &schema.RawExpr{X: "current_time():::TIME"},
},
{
Name: "tTimeWTZ",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "time with time zone", Precision: intp(6)}, Raw: "time with time zone", Null: true},
Default: &schema.RawExpr{X: "current_time():::TIMETZ"},
},
{
Name: "tTimeWOTZ",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "time without time zone", Precision: intp(6)}, Raw: "time without time zone", Null: true},
Default: &schema.RawExpr{X: "current_time():::TIME"},
},
{
Name: "tTimestamp",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp without time zone", Precision: intp(6)}, Raw: "timestamp without time zone", Null: true},
Default: &schema.RawExpr{X: "now():::TIMESTAMP"},
},
{
Name: "tTimestampTZ",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp with time zone", Precision: intp(6)}, Raw: "timestamp with time zone", Null: true},
Default: &schema.RawExpr{X: "now():::TIMESTAMPTZ"},
},
{
Name: "tTimestampWTZ",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp with time zone", Precision: intp(6)}, Raw: "timestamp with time zone", Null: true},
Default: &schema.RawExpr{X: "now():::TIMESTAMPTZ"},
},
{
Name: "tTimestampWOTZ",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp without time zone", Precision: intp(6)}, Raw: "timestamp without time zone", Null: true},
Default: &schema.RawExpr{X: "now():::TIMESTAMP"},
},
{
Name: "tTimestampPrec",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp without time zone", Precision: intp(4)}, Raw: "timestamp without time zone", Null: true},
Default: &schema.RawExpr{X: "now():::TIMESTAMP"},
},
{
Name: "tDouble",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "double precision", Precision: 53}, Raw: "double precision", Null: true},
Default: &schema.RawExpr{X: "0.0:::FLOAT8"},
},
{
Name: "tReal",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "real", Precision: 24}, Raw: "real", Null: true},
Default: &schema.RawExpr{X: "0.0:::FLOAT8"},
},
{
Name: "tFloat8",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "double precision", Precision: 53}, Raw: "double precision", Null: true},
Default: &schema.RawExpr{X: "0.0:::FLOAT8"},
},
{
Name: "tFloat4",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "real", Precision: 24}, Raw: "real", Null: true},
Default: &schema.RawExpr{X: "0.0:::FLOAT8"},
},
{
Name: "tNumeric",
Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 0}, Raw: "numeric", Null: true},
Default: &schema.RawExpr{X: "0:::DECIMAL"},
},
{
Name: "tDecimal",
Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 0}, Raw: "numeric", Null: true},
Default: &schema.RawExpr{X: "0:::DECIMAL"},
},
{
Name: "tSmallSerial",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false}, Raw: "bigint", Null: false},
Default: &schema.RawExpr{
X: "unique_rowid()",
},
},
{
Name: "tSerial",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false}, Raw: "bigint", Null: false},
Default: &schema.RawExpr{
X: "unique_rowid()",
},
},
{
Name: "tBigSerial",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false}, Raw: "bigint", Null: false},
Default: &schema.RawExpr{
X: "unique_rowid()",
},
},
{
Name: "tSerial2",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false}, Raw: "bigint", Null: false},
Default: &schema.RawExpr{
X: "unique_rowid()",
},
},
{
Name: "tSerial4",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false}, Raw: "bigint", Null: false},
Default: &schema.RawExpr{
X: "unique_rowid()",
},
},
{
Name: "tSerial8",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false}, Raw: "bigint", Null: false},
Default: &schema.RawExpr{
X: "unique_rowid()",
},
},
{
Name: "tArray",
Type: &schema.ColumnType{Type: &postgres.ArrayType{Type: &schema.StringType{T: "text"}, T: "text[]"}, Raw: "ARRAY", Null: true},
Default: &schema.RawExpr{
X: "ARRAY[]:::STRING[]",
},
},
{
Name: "tJSON",
Type: &schema.ColumnType{Type: &schema.JSONType{T: "jsonb"}, Raw: "jsonb", Null: true},
Default: &schema.RawExpr{
X: "'{\"key\": \"value\"}':::JSONB",
},
},
{
Name: "tJSONB",
Type: &schema.ColumnType{Type: &schema.JSONType{T: "jsonb"}, Raw: "jsonb", Null: true},
Default: &schema.RawExpr{
X: "'{\"key\": \"value\"}':::JSONB",
},
},
{
Name: "tUUID",
Type: &schema.ColumnType{Type: &postgres.UUIDType{T: "uuid"}, Raw: "uuid", Null: true},
Default: &schema.RawExpr{
X: "'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11':::UUID",
},
},
{
Name: "tInterval",
Type: &schema.ColumnType{Type: &postgres.IntervalType{T: "interval", Precision: intp(6)}, Raw: "interval", Null: true},
Default: &schema.RawExpr{
X: "'04:00:00':::INTERVAL",
},
},
},
}
for i, c := range expected.Columns {
require.EqualValues(t, ts.Columns[i], c, c.Name)
}
})
t.Run("ImplicitIndexes", func(t *testing.T) {
crdbRun(t, func(t *crdbTest) {
testImplicitIndexes(t, t.db)
})
})
}
func (t *crdbTest) url(_ string) string {
return fmt.Sprintf("postgres://root:pass@localhost:%d/defaultdb?sslmode=disable", t.port)
}
func (t *crdbTest) driver() migrate.Driver {
return t.drv
}
func (t *crdbTest) revisionsStorage() migrate.RevisionReadWriter {
return t.rrw
}
func (t *crdbTest) applyHcl(spec string) {
realm := t.loadRealm()
var desired schema.Schema
err := postgres.EvalHCLBytes([]byte(spec), &desired, nil)
require.NoError(t, err)
existing := realm.Schemas[0]
diff, err := t.drv.SchemaDiff(existing, &desired)
require.NoError(t, err)
err = t.drv.ApplyChanges(context.Background(), diff)
require.NoError(t, err)
}
func (t *crdbTest) valueByVersion(values map[string]string, defaults string) string {
if v, ok := values[t.version]; ok {
return v
}
return defaults
}
func (t *crdbTest) loadRealm() *schema.Realm {
r, err := t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{
Schemas: []string{"public"},
Mode: schema.InspectSchemas | schema.InspectTables | schema.InspectTypes,
})
require.NoError(t, err)
return r
}
func (t *crdbTest) loadUsers() *schema.Table {
return t.loadTable("users")
}
func (t *crdbTest) loadPosts() *schema.Table {
return t.loadTable("posts")
}
func (t *crdbTest) loadTable(name string) *schema.Table {
realm := t.loadRealm()
require.Len(t, realm.Schemas, 1)
table, ok := realm.Schemas[0].Table(name)
require.True(t, ok)
return table
}
func (t *crdbTest) users() *schema.Table {
usersT := &schema.Table{
Name: "users",
Schema: t.realm().Schemas[0],
Columns: []*schema.Column{
{
Name: "id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}},
Attrs: []schema.Attr{&postgres.Identity{}},
},
{
Name: "x",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}},
},
},
}
usersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}
return usersT
}
func (t *crdbTest) posts() *schema.Table {
usersT := t.users()
postsT := &schema.Table{
Name: "posts",
Schema: t.realm().Schemas[0],
Columns: []*schema.Column{
{
Name: "id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}},
Attrs: []schema.Attr{&postgres.Identity{}},
},
{
Name: "author_id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.Literal{V: "10"},
},
{
Name: "ctime",
Type: &schema.ColumnType{Raw: "timestamp", Type: &schema.TimeType{T: "timestamp"}},
Default: &schema.RawExpr{
X: "CURRENT_TIMESTAMP",
},
},
},
Attrs: []schema.Attr{
&schema.Comment{Text: "posts comment"},
},
}
postsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}
postsT.Indexes = []*schema.Index{
{Name: "author_id", Parts: []*schema.IndexPart{{C: postsT.Columns[1]}}},
{Name: "id_author_id_unique", Unique: true, Parts: []*schema.IndexPart{{C: postsT.Columns[1]}, {C: postsT.Columns[0]}}},
}
postsT.ForeignKeys = []*schema.ForeignKey{
{Symbol: "author_id", Table: postsT, Columns: postsT.Columns[1:2], RefTable: usersT, RefColumns: usersT.Columns[:1], OnDelete: schema.NoAction},
}
return postsT
}
func (t *crdbTest) realm() *schema.Realm {
r := &schema.Realm{
Schemas: []*schema.Schema{
{
Name: "public",
},
},
}
r.Schemas[0].Realm = r
return r
}
func (t *crdbTest) diff(t1, t2 *schema.Table) []schema.Change {
changes, err := t.drv.TableDiff(t1, t2)
require.NoError(t, err)
return changes
}
func (t *crdbTest) migrate(changes ...schema.Change) {
err := t.drv.ApplyChanges(context.Background(), changes)
require.NoError(t, err)
}
func (t *crdbTest) dropTables(names ...string) {
t.Cleanup(func() {
_, err := t.db.Exec("DROP TABLE IF EXISTS " + strings.Join(names, ", "))
require.NoError(t.T, err, "drop tables %q", names)
})
}
func (t *crdbTest) dropSchemas(names ...string) {
t.Cleanup(func() {
_, err := t.db.Exec("DROP SCHEMA IF EXISTS " + strings.Join(names, ", ") + " CASCADE")
require.NoError(t.T, err, "drop schema %q", names)
})
}
func (t *crdbTest) applyRealmHcl(spec string) {
realm := t.loadRealm()
var desired schema.Realm
err := postgres.EvalHCLBytes([]byte(spec), &desired, nil)
require.NoError(t, err)
diff, err := t.drv.RealmDiff(realm, &desired)
require.NoError(t, err)
err = t.drv.ApplyChanges(context.Background(), diff)
require.NoError(t, err)
}
================================================
FILE: internal/integration/docker-compose.yaml
================================================
services:
mysql56:
container_name: atlas-integration-mysql56
platform: linux/amd64
image: mysql:5.6.35
environment:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
healthcheck:
test: mysqladmin ping -ppass
ports:
- "3306:3306"
mysql57:
container_name: atlas-integration-mysql57
platform: linux/amd64
image: mysql:5.7.26
environment:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
healthcheck:
test: mysqladmin ping -ppass
ports:
- "3307:3306"
mysql8:
container_name: atlas-integration-mysql8
platform: linux/amd64
image: mysql:8.4
environment:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
healthcheck:
test: mysqladmin ping -ppass
ports:
- "3308:3306"
postgres-ext-postgis:
container_name: atlas-integration-postgres-ext-postgis
platform: linux/amd64
image: postgis/postgis:latest
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
healthcheck:
test: pg_isready -U postgres
ports:
- "5429:5432"
postgres10:
container_name: atlas-integration-postgres10
platform: linux/amd64
image: postgres:10
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
healthcheck:
test: pg_isready -U postgres
ports:
- "5430:5432"
postgres11:
container_name: atlas-integration-postgres11
platform: linux/amd64
image: postgres:11
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
healthcheck:
test: pg_isready -U postgres
ports:
- "5431:5432"
postgres12:
container_name: atlas-integration-postgres12
platform: linux/amd64
image: postgres:12
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
healthcheck:
test: pg_isready -U postgres
ports:
- "5432:5432"
postgres13:
container_name: atlas-integration-postgres13
platform: linux/amd64
image: postgres:13
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
healthcheck:
test: pg_isready -U postgres
ports:
- "5433:5432"
postgres14:
container_name: atlas-integration-postgres14
platform: linux/amd64
image: postgres:14
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
healthcheck:
test: pg_isready -U postgres
ports:
- "5434:5432"
postgres15:
container_name: atlas-integration-postgres15
platform: linux/amd64
image: postgres:15
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
healthcheck:
test: pg_isready -U postgres
ports:
- "5435:5432"
mariadb:
container_name: atlas-integration-mariadb
platform: linux/amd64
image: mariadb
environment:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
healthcheck:
test: mysqladmin ping -ppass
ports:
- "4306:3306"
mariadb102:
container_name: atlas-integration-mariadb102
platform: linux/amd64
image: mariadb:10.2.32
environment:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
healthcheck:
test: mysqladmin ping -ppass
ports:
- "4307:3306"
mariadb103:
container_name: atlas-integration-mariadb103
platform: linux/amd64
image: mariadb:10.3.13
environment:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
healthcheck:
test: mysqladmin ping -ppass
ports:
- "4308:3306"
# Default DB test, No Password
tidb5:
container_name: atlas-integration-tidb5
platform: linux/amd64
image: pingcap/tidb:v5.4.0
ports:
- "4309:4000"
tidb6:
container_name: atlas-integration-tidb6
platform: linux/amd64
image: pingcap/tidb:v6.6.0
ports:
- "4310:4000"
cockroach21.2.11:
container_name: atlas-integration-cockroach21.2.11
platform: linux/amd64
image: cockroachdb/cockroach:v21.2.11
ports:
- "26257:26257"
command: "start-single-node --insecure"
================================================
FILE: internal/integration/go.mod
================================================
module ariga.io/atlas/internal/integration
go 1.24.13
replace ariga.io/atlas => ../../
replace ariga.io/atlas/cmd/atlas => ../../cmd/atlas
require (
ariga.io/atlas v0.32.1-0.20250325101103-175b25e1c1b9
ariga.io/atlas/cmd/atlas v0.13.2-0.20231220130200-d8bd6f612d7a
github.com/go-sql-driver/mysql v1.9.3
github.com/hashicorp/hcl/v2 v2.18.1
github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.28
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
github.com/rogpeppe/go-internal v1.13.1
github.com/stretchr/testify v1.11.1
github.com/zclconf/go-cty v1.15.1
)
require (
cloud.google.com/go/auth v0.16.3 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.7.0 // indirect
cloud.google.com/go/iam v1.5.2 // indirect
cloud.google.com/go/longrunning v0.6.7 // indirect
cloud.google.com/go/secretmanager v1.15.0 // indirect
entgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1 // indirect
github.com/agext/levenshtein v1.2.3 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/aws/aws-sdk-go v1.55.7 // indirect
github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect
github.com/aws/aws-sdk-go-v2/config v1.29.17 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
github.com/aws/smithy-go v1.22.4 // indirect
github.com/bmatcuk/doublestar v1.3.4 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/coder/websocket v1.8.12 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/google/wire v0.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d // indirect
github.com/vektah/gqlparser/v2 v2.5.16 // indirect
github.com/zclconf/go-cty-yaml v1.1.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
gocloud.dev v0.43.0 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
golang.org/x/mod v0.26.0 // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/time v0.12.0 // indirect
golang.org/x/tools v0.35.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/api v0.242.0 // indirect
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 // indirect
google.golang.org/grpc v1.73.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
================================================
FILE: internal/integration/go.sum
================================================
cloud.google.com/go v0.121.4 h1:cVvUiY0sX0xwyxPwdSU2KsF9knOVmtRyAMt8xou0iTs=
cloud.google.com/go v0.121.4/go.mod h1:XEBchUiHFJbz4lKBZwYBDHV/rSyfFktk737TLDU089s=
cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc=
cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA=
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.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
cloud.google.com/go/kms v1.22.0 h1:dBRIj7+GDeeEvatJeTB19oYZNV0aj6wEqSIT/7gLqtk=
cloud.google.com/go/kms v1.22.0/go.mod h1:U7mf8Sva5jpOb4bxYZdtw/9zsbIjrklYwPcvMk34AL8=
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
cloud.google.com/go/secretmanager v1.15.0 h1:RtkCMgTpaBMbzozcRUGfZe46jb9a3qh5EdEtVRUATF8=
cloud.google.com/go/secretmanager v1.15.0/go.mod h1:1hQSAhKK7FldiYw//wbR/XPfPc08eQ81oBsnRUHEvUc=
entgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4 h1:d7UZAvQCnOp1PyiHAWkPCXBEPW3tVjraiK/RZlsW0XY=
entgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4/go.mod h1:zTzLmWtPvGpmSwtkaayM2cm5m819NdM7z7tYPq3vN0U=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1 h1:LejjvYg4tCW5HO7q/1nzPrprh47oUD9OUySQ29pDp5c=
github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1/go.mod h1:cnC/60IoLiDM0GhdKYJ6oO7AwpZe1IQfPnSKlAURgHw=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=
github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac=
github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0=
github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=
github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0=
github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8=
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0=
github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8=
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16 h1:j+YO7Khxpk73ESxUpheUSw91qT42+LqNZiEjul1Dmnk=
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16/go.mod h1:laSv+AlZPuT/bpJQ2Xspq/oDKhB/XZLohISGTKU7DOg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7 h1:d+mnMa4JbJlooSbYQfrJpit/YINaB30JEVgrhtjZneA=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7/go.mod h1:1X1NotbcGHH7PCQJ98PsExSxsJj/VWzz8MfFz43+02M=
github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1 h1:OwMzNDe5VVTXD4kGmeK/FtqAITiV8Mw4TCa8IyNO0as=
github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1/go.mod h1:IyVabkWrs8SNdOEZLyFFcW9bUltV4G6OQS0s6H20PHg=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E=
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0=
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w=
github.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
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-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
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.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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/go-replayers/grpcreplay v1.3.0 h1:1Keyy0m1sIpqstQmgz307zhiJ1pV4uIlFds5weTmxbo=
github.com/google/go-replayers/grpcreplay v1.3.0/go.mod h1:v6NgKtkijC0d3e3RW8il6Sy5sqRVUwoQa4mHOGEy8DI=
github.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk=
github.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy+tME4bwyqPcwWbNlUI1Mcg=
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
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/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
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/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/hcl/v2 v2.18.1 h1:6nxnOJFku1EuSawSD81fuviYUV8DxFr3fp2dUi3ZYSo=
github.com/hashicorp/hcl/v2 v2.18.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
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/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
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.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU=
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s=
github.com/vektah/gqlparser/v2 v2.5.16 h1:1gcmLTvs3JLKXckwCwlUagVn/IlV2bwqle0vJ0vy5p8=
github.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zclconf/go-cty v1.15.1 h1:RgQYm4j2EvoBRXOPxhUvxPzRrGDo1eCOhHXuGfrj5S0=
github.com/zclconf/go-cty v1.15.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0=
github.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 h1:rbRJ8BBoVMsQShESYZ0FkvcITu8X8QNwJogcLUmDNNw=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0/go.mod h1:ru6KHrNtNHxM4nD/vd6QrLVWgKhxPYgblq4VAtNawTQ=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
gocloud.dev v0.43.0 h1:aW3eq4RMyehbJ54PMsh4hsp7iX8cO/98ZRzJJOzN/5M=
gocloud.dev v0.43.0/go.mod h1:eD8rkg7LhKUHrzkEdLTZ+Ty/vgPHPCd+yMQdfelQVu4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg=
google.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 h1:Nt6z9UHqSlIdIGJdz6KhTIs2VRx/iOsA5iE8bmQNcxs=
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79/go.mod h1:kTmlBHMPqR5uCZPBvwa2B18mvubkjyY3CRLI0c6fj0s=
google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 h1:iOye66xuaAK0WnkPuhQPUFy8eJcmwUXqGGP3om6IxX8=
google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79/go.mod h1:HKJDgKsFUnv5VAGeQjz8kxcgDP0HoE0iZNp0OdZNlhE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 h1:1ZwqphdOdWYXsUHgMpU/101nCtf/kSp9hOrcvFsnl10=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
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.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
================================================
FILE: internal/integration/hclsqlspec/hclsqlspec_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package hclsqlspec
import (
"math/big"
"testing"
"github.com/zclconf/go-cty/cty"
"ariga.io/atlas/schemahcl"
"ariga.io/atlas/sql/mysql"
"ariga.io/atlas/sql/postgres"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlite"
"ariga.io/atlas/sql/sqlspec"
"github.com/stretchr/testify/require"
)
var dialects = []struct {
name string
schemahcl.Marshaler
Eval func(b []byte, v any, inp map[string]cty.Value) error
}{
{
name: "mysql",
Marshaler: mysql.MarshalHCL,
Eval: mysql.EvalHCLBytes,
},
{
name: "postgres",
Marshaler: postgres.MarshalHCL,
Eval: postgres.EvalHCLBytes,
},
{
name: "sqlite",
Marshaler: sqlite.MarshalHCL,
Eval: sqlite.EvalHCLBytes,
},
}
func TestHCL_SQL(t *testing.T) {
file, err := decode(`
schema "hi" {
}
table "users" {
schema = schema.hi
column "id" {
type = int
null = false
default = 123
}
column "age" {
type = int
null = false
default = 10
}
column "active" {
type = boolean
default = true
}
column "account_active" {
type = boolean
default "DF_expr1" {
as = true
}
}
primary_key {
columns = [table.users.column.id, table.users.column.age]
}
index "age" {
unique = true
columns = [table.users.column.age]
}
index "active" {
unique = false
columns = [table.users.column.active]
}
foreign_key "fk" {
columns = [table.users.column.account_active]
ref_columns = [table.accounts.column.active]
on_delete = "SET NULL"
}
}
table "accounts" {
schema = schema.hi
column "id" {
type = int
null = false
default = 123
}
column "age" {
type = int
null = false
default = 10
}
column "active" {
type = boolean
default = true
}
column "user_active" {
type = boolean
default = true
}
primary_key {
columns = [table.accounts.column.id]
}
index "age" {
unique = true
columns = [table.accounts.column.age]
}
index "active" {
unique = false
columns = [table.accounts.column.active]
}
foreign_key "fk" {
columns = [table.accounts.column.user_active]
ref_columns = [table.users.column.active]
on_delete = "SET NULL"
}
}
`)
require.NoError(t, err)
expected := &db{
Schemas: []*sqlspec.Schema{
{Name: "hi"},
},
Tables: []*sqlspec.Table{
{
Name: "users",
Schema: &schemahcl.Ref{V: "$schema.hi"},
Columns: []*sqlspec.Column{
{
Name: "id",
Type: &schemahcl.Type{T: "int"},
Null: false,
DefaultExtension: schemahcl.DefaultExtension{
Extra: schemahcl.Resource{
Attrs: []*schemahcl.Attr{
{K: "default", V: cty.NumberVal(big.NewFloat(123).SetPrec(512))},
},
},
},
},
{
Name: "age",
Type: &schemahcl.Type{T: "int"},
Null: false,
DefaultExtension: schemahcl.DefaultExtension{
Extra: schemahcl.Resource{
Attrs: []*schemahcl.Attr{
{K: "default", V: cty.NumberVal(big.NewFloat(10).SetPrec(512))},
},
},
},
},
{
Name: "active",
Type: &schemahcl.Type{T: "boolean"},
Null: false,
DefaultExtension: schemahcl.DefaultExtension{
Extra: schemahcl.Resource{
Attrs: []*schemahcl.Attr{
{K: "default", V: cty.BoolVal(true)},
},
},
},
},
{
Name: "account_active",
Type: &schemahcl.Type{T: "boolean"},
Null: false,
DefaultExtension: schemahcl.DefaultExtension{
Extra: schemahcl.Resource{
Children: []*schemahcl.Resource{
{
Type: "default",
Name: "DF_expr1",
Attrs: []*schemahcl.Attr{
{K: "as", V: cty.BoolVal(true)},
},
},
},
},
},
},
},
PrimaryKey: &sqlspec.PrimaryKey{
Columns: []*schemahcl.Ref{
{
V: "$table.users.$column.id",
},
{
V: "$table.users.$column.age",
},
},
},
Indexes: []*sqlspec.Index{
{
Name: "age",
Unique: true,
Columns: []*schemahcl.Ref{
{
V: "$table.users.$column.age",
},
},
},
{
Name: "active",
Unique: false,
Columns: []*schemahcl.Ref{
{
V: "$table.users.$column.active",
},
},
},
},
ForeignKeys: []*sqlspec.ForeignKey{
{
Symbol: "fk",
Columns: []*schemahcl.Ref{
{
V: "$table.users.$column.account_active",
},
},
RefColumns: []*schemahcl.Ref{
{
V: "$table.accounts.$column.active",
},
},
OnDelete: &schemahcl.Ref{V: string(schema.SetNull)},
},
},
},
{
Name: "accounts",
Schema: &schemahcl.Ref{V: "$schema.hi"},
Columns: []*sqlspec.Column{
{
Name: "id",
Type: &schemahcl.Type{T: "int"},
Null: false,
DefaultExtension: schemahcl.DefaultExtension{
Extra: schemahcl.Resource{
Attrs: []*schemahcl.Attr{
{K: "default", V: cty.NumberVal(big.NewFloat(123).SetPrec(512))},
},
},
},
},
{
Name: "age",
Type: &schemahcl.Type{T: "int"},
Null: false,
DefaultExtension: schemahcl.DefaultExtension{
Extra: schemahcl.Resource{
Attrs: []*schemahcl.Attr{
{K: "default", V: cty.NumberVal(big.NewFloat(10).SetPrec(512))},
},
},
},
},
{
Name: "active",
Type: &schemahcl.Type{T: "boolean"},
Null: false,
DefaultExtension: schemahcl.DefaultExtension{
Extra: schemahcl.Resource{
Attrs: []*schemahcl.Attr{
{K: "default", V: cty.BoolVal(true)},
},
},
},
},
{
Name: "user_active",
Type: &schemahcl.Type{T: "boolean"},
Null: false,
DefaultExtension: schemahcl.DefaultExtension{
Extra: schemahcl.Resource{
Attrs: []*schemahcl.Attr{
{K: "default", V: cty.BoolVal(true)},
},
},
},
},
},
PrimaryKey: &sqlspec.PrimaryKey{
Columns: []*schemahcl.Ref{
{
V: "$table.accounts.$column.id",
},
},
},
Indexes: []*sqlspec.Index{
{
Name: "age",
Unique: true,
Columns: []*schemahcl.Ref{
{
V: "$table.accounts.$column.age",
},
},
},
{
Name: "active",
Unique: false,
Columns: []*schemahcl.Ref{
{
V: "$table.accounts.$column.active",
},
},
},
},
ForeignKeys: []*sqlspec.ForeignKey{
{
Symbol: "fk",
Columns: []*schemahcl.Ref{
{
V: "$table.accounts.$column.user_active",
},
},
RefColumns: []*schemahcl.Ref{
{
V: "$table.users.$column.active",
},
},
OnDelete: &schemahcl.Ref{V: string(schema.SetNull)},
},
},
},
},
}
require.EqualValues(t, expected, file)
}
func TestWithRemain(t *testing.T) {
file, err := decode(`
schema "hi" {
x = 1
}`)
require.NoError(t, err)
require.EqualValues(t, &db{
Schemas: []*sqlspec.Schema{
{
Name: "hi",
DefaultExtension: schemahcl.DefaultExtension{
Extra: schemahcl.Resource{
Attrs: []*schemahcl.Attr{
schemahcl.IntAttr("x", 1),
},
},
},
},
},
}, file)
}
func TestMultiTable(t *testing.T) {
_, err := decode(`
schema "hi" {
}
table "users" {
schema = schema.hi
column "id" {
type = int
unsigned = true
null = false
default = 123
}
}
table "accounts" {
schema = schema.hi
column "id" {
type = varchar(255)
}
index "name" {
unique = true
}
}
`)
require.NoError(t, err)
}
var hcl = schemahcl.New(schemahcl.WithTypes("table.column.type", postgres.TypeRegistry.Specs()))
func TestMarshalTopLevel(t *testing.T) {
c := &sqlspec.Schema{
Name: "schema",
}
h, err := hcl.MarshalSpec(c)
require.NoError(t, err)
require.EqualValues(t, `schema "schema" {
}
`, string(h))
}
func TestRealm(t *testing.T) {
f := `schema "account_a" {
}
table "t1" {
schema = schema.account_a
}
schema "account_b" {
}
table "t2" {
schema = schema.account_b
}
`
for _, tt := range dialects {
t.Run(tt.name, func(t *testing.T) {
var r schema.Realm
err := tt.Eval([]byte(f), &r, nil)
require.NoError(t, err)
exp := &schema.Realm{
Schemas: []*schema.Schema{
{
Name: "account_a",
Realm: &r,
Tables: []*schema.Table{
{Name: "t1"},
},
},
{
Name: "account_b",
Realm: &r,
Tables: []*schema.Table{
{Name: "t2"},
},
},
},
}
exp.Schemas[0].Tables[0].Schema = exp.Schemas[0]
exp.Schemas[1].Tables[0].Schema = exp.Schemas[1]
require.EqualValues(t, exp, &r)
hcl, err := tt.MarshalSpec(&r)
require.NoError(t, err)
var after schema.Realm
err = tt.Eval(hcl, &after, nil)
require.NoError(t, err)
require.EqualValues(t, exp, &after)
})
}
}
func TestUnsignedImmutability(t *testing.T) {
f := `table "users" {
schema = schema.test
column "id" {
type = bigint
unsigned = true
}
column "shouldnt" {
type = bigint
}
}
schema "test" {
}`
var s schema.Schema
err := mysql.EvalHCLBytes([]byte(f), &s, nil)
require.NoError(t, err)
tbl := s.Tables[0]
require.EqualValues(t, &schema.IntegerType{T: "bigint", Unsigned: true}, tbl.Columns[0].Type.Type)
require.EqualValues(t, &schema.IntegerType{T: "bigint", Unsigned: false}, tbl.Columns[1].Type.Type)
}
func TestTablesWithQualifiers(t *testing.T) {
h := `
schema "a" {}
schema "b" {}
table "a" "users" {
schema = schema.a
column "id" {
type = int
}
column "friend_id" {
type = int
}
foreign_key "friend_b" {
columns = [column.friend_id]
ref_columns = [table.b.users.column.id]
}
}
table "b" "users" {
schema = schema.b
column "id" {
type = int
}
column "friend_id" {
type = int
}
foreign_key "friend_a" {
columns = [column.friend_id]
ref_columns = [table.a.users.column.id]
}
}
`
var r schema.Realm
err := mysql.EvalHCLBytes([]byte(h), &r, nil)
require.NoError(t, err)
require.EqualValues(t, r.Schemas[0].Tables[0].Columns[0], r.Schemas[1].Tables[0].ForeignKeys[0].RefColumns[0])
require.EqualValues(t, "b", r.Schemas[0].Tables[0].ForeignKeys[0].RefTable.Schema.Name)
}
func TestQualifyMarshal(t *testing.T) {
for _, tt := range dialects {
t.Run(tt.name, func(t *testing.T) {
r := schema.NewRealm(
schema.New("a").
AddTables(
schema.NewTable("users"),
schema.NewTable("tbl_a"),
),
schema.New("b").
AddTables(
schema.NewTable("users"),
schema.NewTable("tbl_b"),
),
schema.New("c").
AddTables(
schema.NewTable("users"),
schema.NewTable("tbl_c"),
),
)
h, err := tt.Marshaler.MarshalSpec(r)
require.NoError(t, err)
expected := `table "a" "users" {
schema = schema.a
}
table "tbl_a" {
schema = schema.a
}
table "b" "users" {
schema = schema.b
}
table "tbl_b" {
schema = schema.b
}
table "c" "users" {
schema = schema.c
}
table "tbl_c" {
schema = schema.c
}
schema "a" {
}
schema "b" {
}
schema "c" {
}
`
require.EqualValues(t, expected, string(h))
})
}
}
func decode(f string) (*db, error) {
d := &db{}
if err := hcl.EvalBytes([]byte(f), d, nil); err != nil {
return nil, err
}
return d, nil
}
type db struct {
Schemas []*sqlspec.Schema `spec:"schema"`
Tables []*sqlspec.Table `spec:"table"`
}
================================================
FILE: internal/integration/integration_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package integration
import (
"bufio"
"bytes"
"context"
"database/sql"
"flag"
"fmt"
"io"
"net"
"os"
"os/exec"
"path/filepath"
"slices"
"strings"
"sync"
"testing"
"text/template"
"ariga.io/atlas/schemahcl"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"github.com/hashicorp/hcl/v2/hclparse"
"github.com/stretchr/testify/require"
)
var (
dbs []io.Closer
flagVersion string
)
func TestMain(m *testing.M) {
flag.StringVar(&flagVersion, "version", "", "[mysql56, postgres10, tidb5, ...] what version to test")
flag.Parse()
code := m.Run()
for _, db := range dbs {
db.Close()
}
os.Exit(code)
}
func TestCLI_Interrupt(t *testing.T) {
var (
stdout, stderr bytes.Buffer
connected = make(chan struct{})
signal = make(chan struct{})
handler = func(c net.Conn) {
connected <- struct{}{}
<-signal // wait for signal sent
c.Close()
}
)
t.Cleanup(func() {
close(connected)
close(signal)
})
// First interrupt will not cancel the process, only print a warning.
var (
port = newListener(t, handler)
cmd = exec.Command(
execPath(t),
"schema", "inspect",
"--url", fmt.Sprintf("postgres://user:pass@localhost:%d/db?sslmode=disable", port), // mock not responding db
)
)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
require.NoError(t, cmd.Start())
<-connected // wait for connection
require.NoError(t, cmd.Process.Signal(os.Interrupt))
signal <- struct{}{}
require.Error(t, cmd.Wait())
require.Equal(t, "\ninterrupt received, wait for exit or ^C to terminate\n", stdout.String())
require.Contains(t, stderr.String(), "read: connection reset by peer") // server closed
// Two interrupts force stop
r, w := io.Pipe()
port = newListener(t, handler)
cmd = exec.Command(
execPath(t),
"schema", "inspect",
"--url", fmt.Sprintf("postgres://user:pass@localhost:%d/db?sslmode=disable", port), // mock not responding db
)
cmd.Stdout = w
require.NoError(t, cmd.Start())
<-connected // wait for connection
require.NoError(t, cmd.Process.Signal(os.Interrupt))
// Wait for the cmd to print the warning (it works, we checked before) and then issue the second signal.
br := bufio.NewReader(r)
_, err := br.ReadString('\n')
require.NoError(t, err)
out, err := br.ReadString('\n')
require.NoError(t, err)
require.Equal(t, "interrupt received, wait for exit or ^C to terminate\n", out)
require.NoError(t, cmd.Process.Signal(os.Interrupt))
require.Error(t, cmd.Wait())
}
func newListener(t *testing.T, handler func(c net.Conn)) int {
a, err := net.ResolveTCPAddr("tcp", "localhost:0")
require.NoError(t, err)
l, err := net.ListenTCP("tcp", a)
require.NoError(t, err)
t.Cleanup(func() { l.Close() })
go func() {
c, err := l.Accept()
require.NoError(t, err)
handler(c)
}()
return l.Addr().(*net.TCPAddr).Port
}
// T holds the elements common between dialect tests.
type T interface {
testing.TB
url(string) string
driver() migrate.Driver
revisionsStorage() migrate.RevisionReadWriter
realm() *schema.Realm
loadRealm() *schema.Realm
users() *schema.Table
loadUsers() *schema.Table
posts() *schema.Table
loadPosts() *schema.Table
loadTable(string) *schema.Table
dropTables(...string)
dropSchemas(...string)
migrate(...schema.Change)
diff(*schema.Table, *schema.Table) []schema.Change
applyHcl(spec string)
applyRealmHcl(spec string)
}
func testAddDrop(t T) {
usersT := t.users()
postsT := t.posts()
petsT := &schema.Table{
Name: "pets",
Schema: usersT.Schema,
Columns: []*schema.Column{
{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}}},
{Name: "owner_id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Null: true}},
},
}
petsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}
petsT.ForeignKeys = []*schema.ForeignKey{
{Symbol: "owner_id", Table: petsT, Columns: petsT.Columns[1:], RefTable: usersT, RefColumns: usersT.Columns[:1]},
}
if tt, ok := t.(interface {
pets(_, _ *schema.Table) *schema.Table
}); ok {
petsT = tt.pets(usersT, postsT)
}
t.dropTables(postsT.Name, usersT.Name, petsT.Name)
t.migrate(&schema.AddTable{T: petsT}, &schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})
ensureNoChange(t, usersT, petsT, postsT)
t.migrate(&schema.DropTable{T: usersT}, &schema.DropTable{T: postsT}, &schema.DropTable{T: petsT})
// Ensure the realm has no tables.
for _, s := range t.loadRealm().Schemas {
require.Empty(t, s.Tables)
}
}
func testRelation(t T) {
usersT, postsT := t.users(), t.posts()
t.dropTables(postsT.Name, usersT.Name)
t.migrate(
&schema.AddTable{T: usersT},
&schema.AddTable{T: postsT},
)
ensureNoChange(t, postsT, usersT)
}
func testImplicitIndexes(t T, db *sql.DB) {
const (
name = "implicit_indexes"
ddl = "create table implicit_indexes(c1 int unique, c2 int unique, unique(c1,c2), unique(c2,c1))"
)
t.dropTables(name)
_, err := db.Exec(ddl)
require.NoError(t, err)
current := t.loadTable(name)
c1, c2 := schema.NewNullIntColumn("c1", "int"), schema.NewNullIntColumn("c2", "int")
desired := schema.NewTable(name).
AddColumns(c1, c2).
AddIndexes(
schema.NewUniqueIndex("").AddColumns(c1),
schema.NewUniqueIndex("").AddColumns(c2),
schema.NewUniqueIndex("").AddColumns(c1, c2),
schema.NewUniqueIndex("").AddColumns(c2, c1),
)
changes := t.diff(current, desired)
require.Empty(t, changes)
desired.AddIndexes(
schema.NewIndex("c1_key").AddColumns(c1),
schema.NewIndex("c2_key").AddColumns(c2),
)
changes = t.diff(current, desired)
require.NotEmpty(t, changes)
t.migrate(&schema.ModifyTable{T: desired, Changes: changes})
ensureNoChange(t, desired)
}
func testHCLIntegration(t T, full string, empty string) {
t.applyHcl(full)
users := t.loadUsers()
posts := t.loadPosts()
t.dropTables(users.Name, posts.Name)
column, ok := users.Column("id")
require.True(t, ok, "expected id column")
require.Equal(t, "users", users.Name)
column, ok = posts.Column("author_id")
require.Equal(t, "author_id", column.Name)
t.applyHcl(empty)
require.Empty(t, t.realm().Schemas[0].Tables)
}
func testCLIMigrateApplyBC(t T, dialect string) {
ctx := context.Background()
t.dropSchemas("bc_test", "bc_test_2", "atlas_schema_revisions")
t.dropTables("bc_tbl", "atlas_schema_revisions")
t.migrate(&schema.AddSchema{S: schema.New("bc_test")})
// Connection to schema with flag will respect flag (also mimics "old" behavior).
out, err := exec.Command(
execPath(t),
"migrate", "apply",
"--allow-dirty", // since database does contain more than one schema
"--dir", "file://testdata/migrations/"+dialect,
"--url", t.url("bc_test"),
"--revisions-schema", "atlas_schema_revisions",
).CombinedOutput()
require.NoError(t, err, string(out))
s, err := t.driver().InspectSchema(ctx, "atlas_schema_revisions", &schema.InspectOptions{
Mode: schema.InspectSchemas | schema.InspectTables,
})
require.NoError(t, err)
_, ok := s.Table("atlas_schema_revisions")
require.True(t, ok)
// Connection to realm will see the existing schema and will not attempt to migrate.
out, err = exec.Command(
execPath(t),
"migrate", "apply",
"--dir", "file://testdata/migrations/"+dialect,
"--url", t.url(""),
).CombinedOutput()
require.NoError(t, err, string(out))
require.Equal(t, "No migration files to execute\n", string(out))
// Connection to schema without flag will error.
out, err = exec.Command(
execPath(t),
"migrate", "apply",
"--dir", "file://testdata/migrations/"+dialect,
"--url", t.url("bc_test"),
).CombinedOutput()
require.Error(t, err)
require.Contains(t, string(out), "We couldn't find a revision table in the connected schema but found one in")
// Providing the flag and we are good.
out, err = exec.Command(
execPath(t),
"migrate", "apply",
"--dir", "file://testdata/migrations/"+dialect,
"--url", t.url("bc_test"),
"--revisions-schema", "atlas_schema_revisions",
).CombinedOutput()
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", string(out))
// Providing the flag to the schema instead will work as well.
t.migrate(
&schema.DropSchema{S: schema.New("bc_test")},
&schema.AddSchema{S: schema.New("bc_test")},
)
out, err = exec.Command(
execPath(t),
"migrate", "apply",
"--dir", "file://testdata/migrations/"+dialect,
"--url", t.url("bc_test"),
"--revisions-schema", "bc_test",
).CombinedOutput()
require.NoError(t, err, string(out))
require.NotContains(t, string(out), "No migration files to execute\n")
// Consecutive attempts do not need the flag anymore.
out, err = exec.Command(
execPath(t),
"migrate", "apply",
"--dir", "file://testdata/migrations/"+dialect,
"--url", t.url("bc_test"),
).CombinedOutput()
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", string(out))
// Last, if bound to schema and no "old" behavior extra schema does
// exist, the revision table will be saved in the connected one.
t.migrate(
&schema.DropSchema{S: schema.New("atlas_schema_revisions")},
&schema.DropSchema{S: schema.New("bc_test")},
&schema.AddSchema{S: schema.New("bc_test_2")},
)
out, err = exec.Command(
execPath(t),
"migrate", "apply",
"--allow-dirty", // since database does contain more than one schema
"--dir", "file://testdata/migrations/"+dialect,
"--url", t.url("bc_test_2"),
).CombinedOutput()
require.NoError(t, err, string(out))
s, err = t.driver().InspectSchema(ctx, "atlas_schema_revisions", &schema.InspectOptions{
Mode: schema.InspectSchemas | schema.InspectTables,
})
require.True(t, schema.IsNotExistError(err))
s, err = t.driver().InspectSchema(ctx, "bc_test_2", &schema.InspectOptions{
Mode: schema.InspectSchemas | schema.InspectTables,
})
require.NoError(t, err)
_, ok = s.Table("atlas_schema_revisions")
require.True(t, ok)
}
func testCLISchemaInspect(t T, h string, url string, eval schemahcl.Evaluator, args ...string) {
t.dropTables("users")
var expected schema.Schema
err := evalBytes([]byte(h), &expected, eval)
require.NoError(t, err)
t.applyHcl(h)
runArgs := []string{
"schema",
"inspect",
"-u",
url,
}
runArgs = append(runArgs, args...)
cmd := exec.Command(execPath(t), runArgs...)
stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
cmd.Stderr = stderr
cmd.Stdout = stdout
require.NoError(t, cmd.Run(), stderr.String())
var actual schema.Schema
err = evalBytes(stdout.Bytes(), &actual, eval)
require.NoError(t, err)
require.Empty(t, stderr.String())
require.Equal(t, expected, actual)
}
func testCLISchemaInspectEnv(t T, h string, env string, eval schemahcl.Evaluator) {
t.dropTables("users")
var expected schema.Schema
err := evalBytes([]byte(h), &expected, eval)
require.NoError(t, err)
t.applyHcl(h)
cmd := exec.Command(execPath(t),
"schema",
"inspect",
"--env",
env,
)
stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
cmd.Stderr = stderr
cmd.Stdout = stdout
require.NoError(t, cmd.Run(), stderr.String())
var actual schema.Schema
err = evalBytes(stdout.Bytes(), &actual, eval)
require.NoError(t, err)
require.Empty(t, stderr.String())
require.Equal(t, expected, actual)
}
// initOnce controls that the cli will only be built once.
var initOnce sync.Once
func execPath(t testing.TB) string {
initOnce.Do(func() {
args := []string{
"build",
"-mod=mod",
"-o", filepath.Join(os.TempDir(), "atlas"),
}
args = append(args, buildFlags...)
args = append(args, "ariga.io/atlas/cmd/atlas")
out, err := exec.Command("go", args...).CombinedOutput()
require.NoError(t, err, string(out))
})
return filepath.Join(os.TempDir(), "atlas")
}
func testCLIMultiSchemaApply(t T, h string, url string, schemas []string, eval schemahcl.Evaluator) {
f := filepath.Join(t.TempDir(), "schema.hcl")
err := os.WriteFile(f, []byte(h), 0644)
require.NoError(t, err)
require.NoError(t, err)
var expected schema.Realm
err = evalBytes([]byte(h), &expected, eval)
require.NoError(t, err)
cmd := exec.Command(execPath(t),
"schema",
"apply",
"-f",
f,
"-u",
url,
"-s",
strings.Join(schemas, ","),
)
stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
cmd.Stderr = stderr
cmd.Stdout = stdout
stdin, err := cmd.StdinPipe()
require.NoError(t, err)
defer stdin.Close()
_, err = io.WriteString(stdin, "\n")
require.NoError(t, cmd.Run(), stderr.String())
require.True(t, strings.Contains(stdout.String(), `CREATE SCHEMA`) || strings.Contains(stdout.String(), `CREATE DATABASE`), "create schema test2")
}
func testCLIMultiSchemaInspect(t T, h string, url string, schemas []string, eval schemahcl.Evaluator) {
var expected schema.Realm
err := evalBytes([]byte(h), &expected, eval)
require.NoError(t, err)
t.applyRealmHcl(h)
cmd := exec.Command(execPath(t),
"schema",
"inspect",
"-u",
url,
"-s",
strings.Join(schemas, ","),
)
stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
cmd.Stderr = stderr
cmd.Stdout = stdout
require.NoError(t, cmd.Run(), stderr.String())
var actual schema.Realm
err = evalBytes(stdout.Bytes(), &actual, eval)
require.NoError(t, err)
require.Empty(t, stderr.String())
require.Equal(t, expected, actual)
}
func testCLISchemaApply(t T, h string, url string, args ...string) {
t.dropTables("users")
f := filepath.Join(t.TempDir(), "schema.hcl")
err := os.WriteFile(f, []byte(h), 0644)
require.NoError(t, err)
runArgs := append([]string{
"schema", "apply",
"-u", url,
"-f", f,
}, args...)
// Append the --dev-url only if it is not already present.
if !slices.Contains(args, "--dev-url") {
args = append(args, "--dev-url", url)
}
cmd := exec.Command(execPath(t), runArgs...)
stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
cmd.Stderr = stderr
cmd.Stdout = stdout
stdin, err := cmd.StdinPipe()
require.NoError(t, err)
defer stdin.Close()
_, err = io.WriteString(stdin, "\n")
require.NoError(t, err)
require.NoError(t, cmd.Run(), stderr.String(), stdout.String())
require.Empty(t, stderr.String(), stderr.String())
require.Contains(t, stdout.String(), "CREATE TABLE")
u := t.loadUsers()
require.NotNil(t, u)
}
func testCLISchemaApplyDry(t T, h string, url string) {
t.dropTables("users")
f := filepath.Join(t.TempDir(), "schema.hcl")
err := os.WriteFile(f, []byte(h), 0644)
require.NoError(t, err)
cmd := exec.Command(execPath(t),
"schema",
"apply",
"-u",
url,
"-f",
f,
"--dry-run",
)
stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
cmd.Stderr = stderr
cmd.Stdout = stdout
stdin, err := cmd.StdinPipe()
require.NoError(t, err)
defer stdin.Close()
_, err = io.WriteString(stdin, "\n")
require.NoError(t, err)
require.NoError(t, cmd.Run(), stderr.String(), stdout.String())
require.Empty(t, stderr.String(), stderr.String())
require.Contains(t, stdout.String(), "CREATE TABLE")
require.NotContains(t, stdout.String(), "Are you sure?", "dry run should not prompt")
realm := t.loadRealm()
_, ok := realm.Schemas[0].Table("users")
require.False(t, ok, "expected users table not to be created")
}
func testCLISchemaApplyAutoApprove(t T, h string, url string, args ...string) {
t.dropTables("users")
f := filepath.Join(t.TempDir(), "schema.hcl")
err := os.WriteFile(f, []byte(h), 0644)
require.NoError(t, err)
runArgs := []string{
"schema",
"apply",
"-u",
url,
"-f",
f,
"--auto-approve",
}
runArgs = append(runArgs, args...)
cmd := exec.Command(execPath(t), runArgs...)
stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
cmd.Stderr = stderr
cmd.Stdout = stdout
require.NoError(t, err)
require.NoError(t, cmd.Run(), stderr.String(), stdout.String())
require.Empty(t, stderr.String(), stderr.String())
require.Contains(t, stdout.String(), "CREATE TABLE")
u := t.loadUsers()
require.NotNil(t, u)
}
func testCLISchemaApplyFromMigrationDir(t T) {
const (
dbname = "apply_migration_dir"
devname = dbname + "_dev"
)
t.dropSchemas(dbname, devname)
t.migrate(&schema.AddSchema{S: schema.New(dbname)}, &schema.AddSchema{S: schema.New(devname)})
defer t.migrate(&schema.DropSchema{S: schema.New(dbname)}, &schema.DropSchema{S: schema.New(devname)})
users, err := t.driver().SchemaDiff(schema.New(""), schema.New("").AddTables(t.users()))
require.NoError(t, err)
usersT := t.users()
usersT.Name = "users_2"
users2, err := t.driver().SchemaDiff(schema.New(""), schema.New("").AddTables(usersT))
require.NoError(t, err)
opts := []migrate.PlanOption{
func(o *migrate.PlanOptions) { o.Indent, o.SchemaQualifier = " ", new(string) },
}
addUsers, err := t.driver().PlanChanges(context.Background(), "", users, opts...)
require.NoError(t, err)
addUsers2, err := t.driver().PlanChanges(context.Background(), "", users2, opts...)
require.NoError(t, err)
var (
fn = func(c []*migrate.Change) string {
var buf strings.Builder
for _, c := range c {
buf.WriteString(c.Cmd)
buf.WriteString("\n")
}
return buf.String()
}
one = fn(addUsers.Changes)
two = fn(addUsers2.Changes)
)
p := t.TempDir()
require.NoError(t, os.WriteFile(filepath.Join(p, "1.sql"), []byte(one), 0644))
require.NoError(t, os.WriteFile(filepath.Join(p, "2.sql"), []byte(two), 0644))
require.NoError(t, exec.Command(
execPath(t),
"migrate", "hash",
"--dir", "file://"+p,
).Run())
// All versions - must contain all migration files.
out, err := exec.Command(
execPath(t),
"schema", "apply",
"-u", t.url(dbname),
"--to", "file://"+p,
"--dev-url", t.url(devname),
"--dry-run",
"--format", "{{ range $c := .Changes.Pending }}{{ println $c.Cmd }}{{ end }}",
).CombinedOutput()
require.NoError(t, err)
// Normalize oss/ent output.
out = bytes.ReplaceAll(out, []byte(";"), []byte(""))
require.Contains(t, string(out), one)
require.Contains(t, string(out), two)
// One version - must contain only file one.
out, err = exec.Command(
execPath(t),
"schema", "apply",
"-u", t.url(dbname),
"--to", "file://"+p+"?version=1",
"--dev-url", t.url(devname),
"--dry-run",
"--format", "{{ range $c := .Changes.Pending }}{{ println $c.Cmd }}{{ end }}",
).CombinedOutput()
require.NoError(t, err)
// Normalize oss/ent output.
out = bytes.ReplaceAll(out, []byte(";"), []byte(""))
require.Contains(t, string(out), one)
require.NotContains(t, string(out), two)
}
func testCLISchemaDiff(t T, url string) {
t.dropTables("users")
cmd := exec.Command(execPath(t),
"schema",
"diff",
"--from",
url,
"--to",
url,
)
stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
cmd.Stderr = stderr
cmd.Stdout = stdout
require.NoError(t, cmd.Run(), stderr.String(), stdout.String())
require.Empty(t, stderr.String(), stderr.String())
require.Contains(t, stdout.String(), "Schemas are synced, no changes to be made.")
}
func ensureNoChange(t T, tables ...*schema.Table) {
realm := t.loadRealm()
require.Equal(t, len(realm.Schemas[0].Tables), len(tables))
for i := range tables {
tt, ok := realm.Schemas[0].Table(tables[i].Name)
require.True(t, ok)
changes := t.diff(tt, tables[i])
require.Emptyf(t, changes, "changes should be empty for table %s, but instead was %#v", tt.Name, changes)
}
}
func testAdvisoryLock(t *testing.T, l schema.Locker) {
t.Run("One", func(t *testing.T) {
unlock, err := l.Lock(context.Background(), "migrate", 0)
require.NoError(t, err)
_, err = l.Lock(context.Background(), "migrate", 0)
require.Equal(t, schema.ErrLocked, err)
require.NoError(t, unlock())
})
t.Run("Multi", func(t *testing.T) {
var unlocks []schema.UnlockFunc
for _, name := range []string{"a", "b", "c"} {
unlock, err := l.Lock(context.Background(), name, 0)
require.NoError(t, err)
unlocks = append(unlocks, unlock)
}
for _, unlock := range unlocks {
require.NoError(t, unlock())
}
})
}
func testExecutor(t T) {
usersT, postsT := t.users(), t.posts()
petsT := &schema.Table{
Name: "pets",
Schema: usersT.Schema,
Columns: []*schema.Column{
{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}}},
{Name: "owner_id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Null: true}},
},
}
petsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}
petsT.ForeignKeys = []*schema.ForeignKey{
{Symbol: "owner_id", Table: petsT, Columns: petsT.Columns[1:], RefTable: usersT, RefColumns: usersT.Columns[:1]},
}
if tt, ok := t.(interface {
pets(_, _ *schema.Table) *schema.Table
}); ok {
petsT = tt.pets(usersT, postsT)
}
t.dropTables(petsT.Name, postsT.Name, usersT.Name)
t.Cleanup(func() {
t.revisionsStorage().(*rrw).clean()
})
dir, err := migrate.NewLocalDir(t.TempDir())
require.NoError(t, err)
f, err := migrate.NewTemplateFormatter(
template.Must(template.New("").Parse("{{ .Name }}.sql")),
template.Must(template.New("").Parse(
`{{ range .Changes }}{{ with .Comment }}-- {{ println . }}{{ end }}{{ printf "%s;\n" .Cmd }}{{ end }}`,
)),
)
require.NoError(t, err)
pl := migrate.NewPlanner(t.driver(), dir, migrate.PlanFormat(f))
require.NoError(t, err)
require.NoError(t, pl.WritePlan(plan(t, "1_users", &schema.AddTable{T: usersT})))
require.NoError(t, pl.WritePlan(plan(t, "2_posts", &schema.AddTable{T: postsT})))
require.NoError(t, pl.WritePlan(plan(t, "3_pets", &schema.AddTable{T: petsT})))
ex, err := migrate.NewExecutor(t.driver(), dir, t.revisionsStorage())
require.NoError(t, err)
require.NoError(t, ex.ExecuteN(context.Background(), 2)) // usersT and postsT
require.Len(t, *t.revisionsStorage().(*rrw), 2)
ensureNoChange(t, postsT, usersT)
require.NoError(t, ex.ExecuteN(context.Background(), 1)) // petsT
require.Len(t, *t.revisionsStorage().(*rrw), 3)
ensureNoChange(t, petsT, postsT, usersT)
require.ErrorIs(t, ex.ExecuteN(context.Background(), 1), migrate.ErrNoPendingFiles)
}
func plan(t T, name string, changes ...schema.Change) *migrate.Plan {
p, err := t.driver().PlanChanges(context.Background(), name, changes)
require.NoError(t, err)
return p
}
type rrw []*migrate.Revision
func (r *rrw) Ident() *migrate.TableIdent {
return &migrate.TableIdent{}
}
func (r *rrw) WriteRevision(_ context.Context, rev *migrate.Revision) error {
for i, rev2 := range *r {
if rev2.Version == rev.Version {
(*r)[i] = rev
return nil
}
}
*r = append(*r, rev)
return nil
}
func (r *rrw) ReadRevision(_ context.Context, v string) (*migrate.Revision, error) {
for _, rev := range *r {
if rev.Version == v {
return rev, nil
}
}
return nil, migrate.ErrRevisionNotExist
}
func (r *rrw) DeleteRevision(_ context.Context, v string) error {
i := -1
for j, r := range *r {
if r.Version == v {
i = j
break
}
}
if i == -1 {
return nil
}
copy((*r)[i:], (*r)[i+1:])
*r = (*r)[:len(*r)-1]
return nil
}
func (r *rrw) ReadRevisions(context.Context) ([]*migrate.Revision, error) {
return *r, nil
}
func (r *rrw) clean() {
*r = []*migrate.Revision{}
}
var (
buildFlags []string
_ migrate.RevisionReadWriter = (*rrw)(nil)
buildOnce sync.Once
)
func cliPath(t testing.TB) string {
path := filepath.Join(os.TempDir(), "atlas")
buildOnce.Do(func() {
args := append([]string{"build"}, buildFlags...)
args = append(args, "-o", path, "ariga.io/atlas/cmd/atlas")
out, err := exec.Command("go", args...).CombinedOutput()
require.NoError(t, err, string(out))
})
return path
}
func evalBytes(b []byte, v any, ev schemahcl.Evaluator) error {
p := hclparse.NewParser()
if _, diag := p.ParseHCL(b, ""); diag.HasErrors() {
return diag
}
return ev.Eval(p, v, nil)
}
================================================
FILE: internal/integration/mysql_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package integration
import (
"context"
"database/sql"
"fmt"
"os/exec"
"strings"
"sync"
"sync/atomic"
"testing"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/mysql"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
_ "github.com/go-sql-driver/mysql"
"github.com/stretchr/testify/require"
)
type myTest struct {
*testing.T
db *sql.DB
drv migrate.Driver
rrw migrate.RevisionReadWriter
version string
port int
once sync.Once
}
var myTests = map[string]*myTest{
"mysql56": {port: 3306},
"mysql57": {port: 3307},
"mysql8": {port: 3308},
"maria107": {port: 4306},
"maria102": {port: 4307},
"maria103": {port: 4308},
}
func myRun(t *testing.T, fn func(*myTest)) {
for version, tt := range myTests {
if flagVersion == "" || flagVersion == version {
t.Run(version, func(t *testing.T) {
tt.once.Do(func() {
tt.version = version
tt.rrw = &rrw{}
c, err := sqlclient.Open(context.Background(), fmt.Sprintf("mysql://root:pass@localhost:%d/test?parseTime=true", tt.port))
require.NoError(t, err)
tt.drv, tt.db = c.Driver, c.DB
// Close connection after all tests have been run.
dbs = append(dbs, tt.db)
})
tt := &myTest{T: t, db: tt.db, drv: tt.drv, version: version, port: tt.port, rrw: tt.rrw}
fn(tt)
})
}
}
}
func TestMySQL_Executor(t *testing.T) {
myRun(t, func(t *myTest) {
testExecutor(t)
})
}
func TestMySQL_AddDropTable(t *testing.T) {
myRun(t, func(t *myTest) {
testAddDrop(t)
})
}
func TestMySQL_Relation(t *testing.T) {
myRun(t, func(t *myTest) {
testRelation(t)
})
}
func TestMySQL_AddIndexedColumns(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
usersT.Columns = append(usersT.Columns, &schema.Column{
Name: "a",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.RawExpr{X: "10"},
}, &schema.Column{
Name: "b",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.RawExpr{X: "10"},
}, &schema.Column{
Name: "c",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.RawExpr{X: "10"},
})
parts := usersT.Columns[len(usersT.Columns)-3:]
usersT.Indexes = append(usersT.Indexes, &schema.Index{
Unique: true,
Name: "a_b_c_unique",
Parts: []*schema.IndexPart{{C: parts[0]}, {C: parts[1]}, {C: parts[2]}},
})
changes := t.diff(t.loadUsers(), usersT)
require.NotEmpty(t, changes, "usersT contains 2 new columns and 1 new index")
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// In MySQL, dropping a column should remove it from the key.
// However, on MariaDB an explicit DROP/ADD INDEX is required.
if t.mariadb() {
idx, ok := usersT.Index("a_b_c_unique")
require.True(t, ok)
idx.Parts = idx.Parts[:len(idx.Parts)-1]
}
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
changes = t.diff(t.loadUsers(), usersT)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, t.loadUsers())
// Dropping a column from both table and index.
usersT = t.loadUsers()
idx, ok := usersT.Index("a_b_c_unique")
require.True(t, ok)
require.Len(t, idx.Parts, 2)
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
idx.Parts = idx.Parts[:len(idx.Parts)-1]
changes = t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, t.loadUsers())
// Dropping a column should remove
// single-column keys as well.
usersT = t.loadUsers()
idx, ok = usersT.Index("a_b_c_unique")
require.True(t, ok)
require.Len(t, idx.Parts, 1)
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
changes = t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, t.loadUsers())
idx, ok = t.loadUsers().Index("a_b_c_unique")
require.False(t, ok)
})
}
func TestMySQL_AddColumns(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := t.users()
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
usersT.Columns = append(
usersT.Columns,
&schema.Column{Name: "a", Type: &schema.ColumnType{Raw: "tinyblob", Type: &schema.BinaryType{T: "tinyblob"}}},
&schema.Column{Name: "b", Type: &schema.ColumnType{Raw: "mediumblob", Type: &schema.BinaryType{T: "mediumblob"}}},
&schema.Column{Name: "c", Type: &schema.ColumnType{Raw: "blob", Type: &schema.BinaryType{T: "blob"}}},
&schema.Column{Name: "d", Type: &schema.ColumnType{Raw: "longblob", Type: &schema.BinaryType{T: "longblob"}}},
&schema.Column{Name: "e", Type: &schema.ColumnType{Raw: "binary", Type: &schema.BinaryType{T: "binary"}}},
&schema.Column{Name: "f", Type: &schema.ColumnType{Raw: "varbinary(255)", Type: &schema.BinaryType{T: "varbinary(255)"}}, Default: &schema.Literal{V: "foo"}},
&schema.Column{Name: "g", Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar", Size: 255}}},
&schema.Column{Name: "h", Type: &schema.ColumnType{Raw: "varchar(255)", Type: &schema.StringType{T: "varchar(255)"}}},
&schema.Column{Name: "i", Type: &schema.ColumnType{Raw: "tinytext", Type: &schema.StringType{T: "tinytext"}}},
&schema.Column{Name: "j", Type: &schema.ColumnType{Raw: "mediumtext", Type: &schema.StringType{T: "mediumtext"}}},
&schema.Column{Name: "k", Type: &schema.ColumnType{Raw: "text", Type: &schema.StringType{T: "text"}}},
&schema.Column{Name: "l", Type: &schema.ColumnType{Raw: "longtext", Type: &schema.StringType{T: "longtext"}}},
&schema.Column{Name: "m", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "decimal", Precision: 10, Scale: 6}}},
&schema.Column{Name: "m1", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "decimal"}}},
&schema.Column{Name: "m2", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "decimal", Precision: 2}}},
&schema.Column{Name: "n", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 10, Scale: 2}}},
&schema.Column{Name: "n1", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric"}}},
&schema.Column{Name: "n2", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 2}}},
&schema.Column{Name: "o", Type: &schema.ColumnType{Type: &schema.FloatType{T: "float", Precision: 2}}},
&schema.Column{Name: "p", Type: &schema.ColumnType{Type: &schema.FloatType{T: "double", Precision: 14}}},
&schema.Column{Name: "q", Type: &schema.ColumnType{Type: &schema.FloatType{T: "real", Precision: 14}}},
&schema.Column{Name: "r", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}},
&schema.Column{Name: "s", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}}},
&schema.Column{Name: "t", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "smallint"}}},
&schema.Column{Name: "u", Type: &schema.ColumnType{Type: &schema.EnumType{T: "enum", Values: []string{"a", "b", "c"}}}},
&schema.Column{Name: "v", Type: &schema.ColumnType{Type: &schema.StringType{T: "char(36)"}}},
&schema.Column{Name: "x", Type: &schema.ColumnType{Type: &schema.SpatialType{T: "line"}}},
&schema.Column{Name: "y", Type: &schema.ColumnType{Type: &schema.SpatialType{T: "point"}}},
&schema.Column{Name: "z", Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp"}}, Default: &schema.RawExpr{X: "CURRENT_TIMESTAMP"}},
)
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 28)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
}
func TestMySQL_ColumnInt(t *testing.T) {
t.Run("ChangeType", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
for _, typ := range []string{"tinyint", "smallint", "mediumint", "bigint"} {
usersT.Columns[0].Type.Type = &schema.IntegerType{T: typ}
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
}
})
})
t.Run("ChangeDefault", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}, Default: &schema.RawExpr{X: "1"}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
for _, x := range []string{"2", "'3'", "10.1"} {
usersT.Columns[0].Default.(*schema.RawExpr).X = x
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
}
})
})
}
func TestMySQL_ColumnString(t *testing.T) {
t.Run("ChangeType", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar(20)"}}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
for _, typ := range []string{"varchar(255)", "char(120)", "tinytext", "mediumtext", "longtext"} {
usersT.Columns[0].Type.Type = &schema.StringType{T: typ}
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
}
})
})
t.Run("AddWithDefault", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "a", Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar(255)"}}, Default: &schema.RawExpr{X: "hello"}},
{Name: "b", Type: &schema.ColumnType{Type: &schema.StringType{T: "char(255)"}}, Default: &schema.RawExpr{X: "'world'"}},
},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
})
})
t.Run("ChangeDefault", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar(255)"}}, Default: &schema.RawExpr{X: "hello"}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
for _, x := range []string{"2", "'3'", "'world'"} {
usersT.Columns[0].Default.(*schema.RawExpr).X = x
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
}
})
})
}
func TestMySQL_ColumnBool(t *testing.T) {
t.Run("Add", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "a", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}},
{Name: "b", Type: &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}}},
{Name: "c", Type: &schema.ColumnType{Type: &schema.BoolType{T: "tinyint"}}},
{Name: "d", Type: &schema.ColumnType{Type: &schema.BoolType{T: "tinyint(1)"}}},
},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
})
})
t.Run("AddWithDefault", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "a", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "1"}},
{Name: "b", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "0"}},
{Name: "c", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "'1'"}},
{Name: "d", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "'0'"}},
{Name: "e", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "true"}},
{Name: "f", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "false"}},
{Name: "g", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "TRUE"}},
{Name: "h", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "FALSE"}},
},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
})
})
t.Run("ChangeDefault", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "a", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "1"}},
},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
// Change default from "true" to "false" to "true".
for _, x := range []string{"false", "true"} {
usersT.Columns[0].Default.(*schema.RawExpr).X = x
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
}
})
})
t.Run("ChangeNull", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "a", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}, Null: true}},
},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
usersT.Columns[0].Type.Null = false
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
})
}
func TestMySQL_ColumnCheck(t *testing.T) {
myRun(t, func(t *myTest) {
// Checks are not supported in all versions.
if t.version == "mysql56" || t.version == "mysql57" {
t.Skip()
}
usersT := &schema.Table{
Name: "users",
Attrs: []schema.Attr{schema.NewCheck().SetName("users_c_check").SetExpr("c > 5")},
Columns: []*schema.Column{
{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}},
{Name: "c", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}},
},
}
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
ensureNoChange(t, usersT)
})
}
func TestMySQL_ForeignKey(t *testing.T) {
t.Run("ChangeAction", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT, postsT := t.users(), t.posts()
t.dropTables(postsT.Name, usersT.Name)
t.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})
ensureNoChange(t, postsT, usersT)
postsT = t.loadPosts()
fk, ok := postsT.ForeignKey("author_id")
require.True(t, ok)
fk.OnUpdate = schema.SetNull
fk.OnDelete = schema.Cascade
changes := t.diff(t.loadPosts(), postsT)
require.Len(t, changes, 1)
modifyF, ok := changes[0].(*schema.ModifyForeignKey)
require.True(t, ok)
require.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)
t.migrate(&schema.ModifyTable{T: postsT, Changes: changes})
ensureNoChange(t, postsT, usersT)
})
})
t.Run("UnsetNull", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT, postsT := t.users(), t.posts()
t.dropTables(postsT.Name, usersT.Name)
fk, ok := postsT.ForeignKey("author_id")
require.True(t, ok)
fk.OnDelete = schema.SetNull
fk.OnUpdate = schema.SetNull
t.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})
ensureNoChange(t, postsT, usersT)
postsT = t.loadPosts()
c, ok := postsT.Column("author_id")
require.True(t, ok)
c.Type.Null = false
fk, ok = postsT.ForeignKey("author_id")
require.True(t, ok)
fk.OnUpdate = schema.NoAction
fk.OnDelete = schema.NoAction
changes := t.diff(t.loadPosts(), postsT)
require.Len(t, changes, 2)
modifyC, ok := changes[0].(*schema.ModifyColumn)
require.True(t, ok)
require.True(t, modifyC.Change == schema.ChangeNull)
modifyF, ok := changes[1].(*schema.ModifyForeignKey)
require.True(t, ok)
require.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)
t.migrate(&schema.ModifyTable{T: postsT, Changes: changes})
ensureNoChange(t, postsT, usersT)
})
})
t.Run("AddDrop", func(t *testing.T) {
myRun(t, func(t *myTest) {
usersT := t.users()
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
ensureNoChange(t, usersT)
// Add foreign key.
usersT.Columns = append(usersT.Columns, &schema.Column{
Name: "spouse_id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
})
usersT.ForeignKeys = append(usersT.ForeignKeys, &schema.ForeignKey{
Symbol: "spouse_id",
Table: usersT,
Columns: usersT.Columns[len(usersT.Columns)-1:],
RefTable: usersT,
RefColumns: usersT.Columns[:1],
OnDelete: schema.NoAction,
})
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
addC, ok := changes[0].(*schema.AddColumn)
require.True(t, ok)
require.Equal(t, "spouse_id", addC.C.Name)
addF, ok := changes[1].(*schema.AddForeignKey)
require.True(t, ok)
require.Equal(t, "spouse_id", addF.F.Symbol)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// Drop foreign keys.
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
usersT.ForeignKeys = usersT.ForeignKeys[:len(usersT.ForeignKeys)-1]
changes = t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
})
}
func TestMySQL_AdvisoryLock(t *testing.T) {
myRun(t, func(t *myTest) {
testAdvisoryLock(t.T, t.drv.(schema.Locker))
})
}
func TestMySQL_HCL(t *testing.T) {
full := `
schema "test" {
}
table "users" {
schema = schema.test
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
table "posts" {
schema = schema.test
column "id" {
type = int
}
column "author_id" {
type = int
}
foreign_key "author" {
columns = [
table.posts.column.author_id,
]
ref_columns = [
table.users.column.id,
]
}
primary_key {
columns = [table.users.column.id]
}
}
`
empty := `
schema "test" {
}
`
myRun(t, func(t *myTest) {
testHCLIntegration(t, full, empty)
})
}
func TestMySQL_Snapshot(t *testing.T) {
myRun(t, func(t *myTest) {
db, err := sql.Open("mysql", fmt.Sprintf("root:pass@tcp(localhost:%d)/", t.port))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, db.Close())
})
drv, err := mysql.Open(db)
require.NoError(t, err)
_, err = drv.Snapshot(context.Background())
require.ErrorAs(t, err, new(*migrate.NotCleanError))
r, err := t.driver().InspectRealm(context.Background(), &schema.InspectRealmOption{
Mode: schema.InspectSchemas | schema.InspectTables,
})
require.NoError(t, err)
restore, err := t.driver().Snapshot(context.Background())
require.NoError(t, err) // connected to test schema
t.migrate(&schema.AddTable{T: schema.NewTable("my_table").AddColumns(
schema.NewIntColumn("col_1", "integer").SetNull(true),
schema.NewIntColumn("col_2", "bigint"),
)})
t.Cleanup(func() {
t.dropTables("my_table")
})
require.NoError(t, restore(context.Background()))
r1, err := t.driver().InspectRealm(context.Background(), &schema.InspectRealmOption{
Mode: schema.InspectSchemas | schema.InspectTables,
})
require.NoError(t, err)
diff, err := t.driver().RealmDiff(r1, r)
require.NoError(t, err)
require.Zero(t, diff)
})
}
func TestMySQL_CLI_MigrateApplyBC(t *testing.T) {
myRun(t, func(t *myTest) {
testCLIMigrateApplyBC(t, "mysql")
})
}
func TestMySQL_CLI_MigrateApplyLock(t *testing.T) {
myRun(t, func(t *myTest) {
t.dropSchemas("mysqlock")
t.migrate(&schema.AddSchema{S: schema.New("mysqlock")})
var (
b atomic.Bool
wg sync.WaitGroup
)
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
out, err := exec.Command(
execPath(t),
"migrate", "apply",
"--dir", "file://testdata/migrations/mysqlock",
"--url", t.url("mysqlock"),
).CombinedOutput()
require.NoError(t, err, string(out))
switch {
// Nop.
case err == nil && strings.HasPrefix(string(out), "No migration files to execute"):
// Successful run.
case err == nil && strings.HasPrefix(string(out), "Migrating to version 3"):
if b.Swap(true) {
t.Errorf("migration ran twice: %s", out)
}
}
}(i)
}
wg.Wait()
require.True(t, b.Load(), "Migration should run successfully exactly once")
})
}
func TestMySQL_CLI(t *testing.T) {
h := `
schema "test" {
charset = "%s"
collation = "%s"
}
table "users" {
schema = schema.test
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}`
t.Run("SchemaInspect", func(t *testing.T) {
myRun(t, func(t *myTest) {
attrs := t.defaultAttrs()
charset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)
testCLISchemaInspect(t, fmt.Sprintf(h, charset.V, collate.V), t.url("test"), mysql.EvalHCL)
})
})
t.Run("SchemaApply", func(t *testing.T) {
myRun(t, func(t *myTest) {
attrs := t.defaultAttrs()
charset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)
testCLISchemaApply(t, fmt.Sprintf(h, charset.V, collate.V), t.url("test"))
})
})
t.Run("SchemaApplyWithVars", func(t *testing.T) {
h := `
variable "tenant" {
type = string
}
schema "tenant" {
name = var.tenant
}
table "users" {
schema = schema.tenant
column "id" {
type = int
}
}
`
myRun(t, func(t *myTest) {
testCLISchemaApply(t, h, t.url("test"), "--var", "tenant=test")
})
})
t.Run("SchemaApplyDryRun", func(t *testing.T) {
myRun(t, func(t *myTest) {
attrs := t.defaultAttrs()
charset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)
testCLISchemaApplyDry(t, fmt.Sprintf(h, charset.V, collate.V), t.url("test"))
})
})
t.Run("SchemaDiffRun", func(t *testing.T) {
myRun(t, func(t *myTest) {
testCLISchemaDiff(t, t.url("test"))
})
})
t.Run("SchemaApplyAutoApprove", func(t *testing.T) {
myRun(t, func(t *myTest) {
attrs := t.defaultAttrs()
charset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)
testCLISchemaApplyAutoApprove(t, fmt.Sprintf(h, charset.V, collate.V), t.url("test"))
})
})
t.Run("SchemaApplyFromMigrationDir", func(t *testing.T) {
myRun(t, func(t *myTest) {
testCLISchemaApplyFromMigrationDir(t)
})
})
}
func TestMySQL_CLI_MultiSchema(t *testing.T) {
h := `
schema "test" {
charset = "%s"
collation = "%s"
}
table "test" "users" {
schema = schema.test
column "id" {
type = int
}
primary_key {
columns = [column.id]
}
}
schema "test2" {
charset = "%s"
collation = "%s"
}
table "test2" "users" {
schema = schema.test2
column "id" {
type = int
}
primary_key {
columns = [column.id]
}
}`
t.Run("SchemaInspect", func(t *testing.T) {
myRun(t, func(t *myTest) {
t.dropSchemas("test2")
t.dropTables("users")
attrs := t.defaultAttrs()
charset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)
testCLIMultiSchemaInspect(t, fmt.Sprintf(h, charset.V, collate.V, charset.V, collate.V), t.url(""), []string{"test", "test2"}, mysql.EvalHCL)
})
})
t.Run("SchemaApply", func(t *testing.T) {
myRun(t, func(t *myTest) {
t.dropSchemas("test2")
t.dropTables("users")
attrs := t.defaultAttrs()
charset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)
testCLIMultiSchemaApply(t, fmt.Sprintf(h, charset.V, collate.V, charset.V, collate.V), t.url(""), []string{"test", "test2"}, mysql.EvalHCL)
})
})
}
func TestMySQL_HCL_Realm(t *testing.T) {
myRun(t, func(t *myTest) {
t.dropSchemas("second")
realm := t.loadRealm()
hcl, err := mysql.MarshalHCL(realm)
require.NoError(t, err)
wa := string(hcl) + `
schema "second" {
}
`
t.applyRealmHcl(wa)
realm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{
Mode: schema.InspectSchemas | schema.InspectTables,
})
require.NoError(t, err)
_, ok := realm.Schema("test")
require.True(t, ok)
_, ok = realm.Schema("second")
require.True(t, ok)
})
}
func TestMySQL_HCL_ForeignKeyCrossSchema(t *testing.T) {
const expected = `table "credit_cards" {
schema = schema.financial
column "id" {
null = false
type = int
}
column "user_id" {
null = false
type = int
}
primary_key {
columns = [column.id]
}
foreign_key "user_id_fkey" {
columns = [column.user_id]
ref_columns = [table.users.users.column.id]
on_update = NO_ACTION
on_delete = NO_ACTION
}
index "user_id_fkey" {
columns = [column.user_id]
}
}
table "financial" "users" {
schema = schema.financial
column "id" {
null = false
type = int
}
}
table "users" "users" {
schema = schema.users
column "id" {
null = false
type = int
}
column "email" {
null = false
type = varchar(255)
}
primary_key {
columns = [column.id]
}
}
schema "financial" {
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
schema "users" {
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
`
myRun(t, func(t *myTest) {
t.dropSchemas("financial", "users")
realm := t.loadRealm()
hcl, err := mysql.MarshalHCL(realm)
require.NoError(t, err)
t.applyRealmHcl(string(hcl) + "\n" + expected)
realm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{
Mode: schema.InspectSchemas | schema.InspectTables,
Schemas: []string{"users", "financial"},
})
require.NoError(t, err)
actual, err := mysql.MarshalHCL(realm)
require.NoError(t, err)
require.Equal(t, expected, string(actual))
})
}
func TestMySQL_DefaultsHCL(t *testing.T) {
n := "atlas_defaults"
myRun(t, func(t *myTest) {
ddl := `
create table atlas_defaults
(
string varchar(255) default "hello_world",
quoted varchar(100) default 'never say "never"',
tBit bit(10) default b'10101',
ts timestamp default CURRENT_TIMESTAMP,
number int default 42
)
`
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
spec, err := mysql.MarshalHCL(realm.Schemas[0])
require.NoError(t, err)
var s schema.Realm
err = mysql.EvalHCLBytes(spec, &s, nil)
require.NoError(t, err)
t.dropTables(n)
t.applyHcl(string(spec))
ensureNoChange(t, realm.Schemas[0].Tables[0])
})
}
func TestMySQL_Sanity(t *testing.T) {
n := "atlas_types_sanity"
t.Run("Common", func(t *testing.T) {
ddl := `
create table atlas_types_sanity
(
tBit bit(10) default b'100' null,
tInt int(10) default 4 not null,
tTinyInt tinyint(10) default 8 null,
tSmallInt smallint(10) default 2 null,
tMediumInt mediumint(10) default 11 null,
tBigInt bigint(10) default 4 null,
tDecimal decimal default 4 null,
tNumeric numeric default 4 not null,
tFloat float(10, 0) default 4 null,
tDouble double(10, 0) default 4 null,
tReal double(10, 0) default 4 null,
tTimestamp timestamp default CURRENT_TIMESTAMP null,
tTimestampFraction timestamp(6) default CURRENT_TIMESTAMP(6) null,
tTimestampOnUpdate timestamp default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP null,
tTimestampFractionOnUpdate timestamp(6) default CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) null,
tDate date null,
tTime time null,
tDateTime datetime null,
tYear year null,
tVarchar varchar(10) default 'Titan' null,
tChar char(25) default 'Olimpia' not null,
tVarBinary varbinary(30) default 'Titan' null,
tBinary binary(5) default 'Titan' null,
tBlob blob(5) default null,
tTinyBlob tinyblob null,
tMediumBlob mediumblob default null,
tLongBlob longblob default null,
tText text(13) default null,
tTinyText tinytext default null,
tMediumText mediumtext default null,
tLongText longtext default null,
tEnum enum('a','b') default null,
tSet set('a','b') default null,
tGeometry geometry default null,
tPoint point default null,
tMultiPoint multipoint default null,
tLineString linestring default null,
tMultiLineString multilinestring default null,
tPolygon polygon default null,
tMultiPolygon multipolygon default null,
tGeometryCollection geometrycollection default null
) CHARSET = latin1 COLLATE latin1_swedish_ci;
`
myRun(t, func(t *myTest) {
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
require.Len(t, realm.Schemas, 1)
ts, ok := realm.Schemas[0].Table(n)
require.True(t, ok)
expected := schema.Table{
Name: n,
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_swedish_ci"},
&mysql.Engine{V: "InnoDB", Default: true},
},
Schema: realm.Schemas[0],
Columns: []*schema.Column{
{
Name: "tBit",
Type: &schema.ColumnType{Type: &mysql.BitType{T: "bit", Size: 10}, Raw: "bit(10)", Null: true},
Default: &schema.Literal{V: "b'100'"},
},
{
Name: "tInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int", Unsigned: false},
Raw: t.valueByVersion(map[string]string{"mysql8": "int"}, "int(10)"), Null: false},
Default: &schema.Literal{V: "4"},
},
{
Name: "tTinyInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "tinyint", Unsigned: false},
Raw: t.valueByVersion(map[string]string{"mysql8": "tinyint"}, "tinyint(10)"), Null: true},
Default: &schema.Literal{V: "8"},
},
{
Name: "tSmallInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "smallint", Unsigned: false},
Raw: t.valueByVersion(map[string]string{"mysql8": "smallint"}, "smallint(10)"), Null: true},
Default: &schema.Literal{V: "2"},
},
{
Name: "tMediumInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "mediumint", Unsigned: false},
Raw: t.valueByVersion(map[string]string{"mysql8": "mediumint"}, "mediumint(10)"), Null: true},
Default: &schema.Literal{V: "11"},
},
{
Name: "tBigInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false},
Raw: t.valueByVersion(map[string]string{"mysql8": "bigint"}, "bigint(10)"), Null: true},
Default: &schema.Literal{V: "4"},
},
{
Name: "tDecimal",
Type: &schema.ColumnType{Type: &schema.DecimalType{T: "decimal", Precision: 10},
Raw: "decimal(10,0)", Null: true},
Default: &schema.Literal{V: "4"},
},
{
Name: "tNumeric",
Type: &schema.ColumnType{Type: &schema.DecimalType{T: "decimal", Precision: 10},
Raw: "decimal(10,0)", Null: false},
Default: &schema.Literal{V: "4"},
},
{
Name: "tFloat",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "float", Precision: 10},
Raw: "float(10,0)", Null: true},
Default: &schema.Literal{V: "4"},
},
{
Name: "tDouble",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "double", Precision: 10},
Raw: "double(10,0)", Null: true},
Default: &schema.Literal{V: "4"},
},
{
Name: "tReal",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "double", Precision: 10},
Raw: "double(10,0)", Null: true},
Default: &schema.Literal{V: "4"},
},
{
Name: "tTimestamp",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp"},
Raw: "timestamp", Null: true},
Default: &schema.RawExpr{
X: func() string {
if t.mariadb() {
return "(current_timestamp())"
}
return "CURRENT_TIMESTAMP"
}(),
},
},
{
Name: "tTimestampFraction",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp", Precision: intp(6)},
Raw: "timestamp(6)", Null: true},
Default: &schema.RawExpr{
X: func() string {
if t.mariadb() {
return "(current_timestamp(6))"
}
return "CURRENT_TIMESTAMP(6)"
}(),
},
},
{
Name: "tTimestampOnUpdate",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp"},
Raw: "timestamp", Null: true},
Default: &schema.RawExpr{
X: func() string {
if t.mariadb() {
return "(current_timestamp())"
}
return "CURRENT_TIMESTAMP"
}(),
},
Attrs: []schema.Attr{
&mysql.OnUpdate{
A: func() string {
if t.mariadb() {
return "current_timestamp()"
}
return "CURRENT_TIMESTAMP"
}(),
},
},
},
{
Name: "tTimestampFractionOnUpdate",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp", Precision: intp(6)}, Raw: "timestamp(6)", Null: true},
Default: &schema.RawExpr{
X: func() string {
if t.mariadb() {
return "(current_timestamp(6))"
}
return "CURRENT_TIMESTAMP(6)"
}(),
},
Attrs: []schema.Attr{
&mysql.OnUpdate{
A: func() string {
if t.mariadb() {
return "current_timestamp(6)"
}
return "CURRENT_TIMESTAMP(6)"
}(),
},
},
},
{
Name: "tDate",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "date"},
Raw: "date", Null: true},
},
{
Name: "tTime",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "time"},
Raw: "time", Null: true},
},
{
Name: "tDateTime",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "datetime"},
Raw: "datetime", Null: true},
},
{
Name: "tYear",
Type: &schema.ColumnType{
Type: &schema.TimeType{
T: "year",
Precision: func() *int {
// From MySQL 8.0.19, display width is deprecated in YEAR types.
if t.version == "mysql8" {
return nil
}
p := 4
return &p
}(),
},
Raw: t.valueByVersion(map[string]string{"mysql8": "year"}, "year(4)"), Null: true},
},
{
Name: "tVarchar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar", Size: 10},
Raw: "varchar(10)", Null: true},
Default: &schema.Literal{V: t.quoted("Titan")},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_swedish_ci"},
},
},
{
Name: "tChar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "char", Size: 25},
Raw: "char(25)", Null: false},
Default: &schema.Literal{V: t.quoted("Olimpia")},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_swedish_ci"},
},
},
{
Name: "tVarBinary",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "varbinary", Size: intp(30)},
Raw: "varbinary(30)", Null: true},
Default: &schema.Literal{V: t.valueByVersion(map[string]string{"mysql8": "0x546974616E"}, t.quoted("Titan"))},
},
{
Name: "tBinary",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "binary", Size: intp(5)},
Raw: "binary(5)", Null: true},
Default: &schema.Literal{V: t.valueByVersion(map[string]string{"mysql8": "0x546974616E"}, t.quoted("Titan"))},
},
{
Name: "tBlob",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "tinyblob"},
Raw: "tinyblob", Null: true},
},
{
Name: "tTinyBlob",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "tinyblob"},
Raw: "tinyblob", Null: true},
},
{
Name: "tMediumBlob",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "mediumblob"},
Raw: "mediumblob", Null: true},
},
{
Name: "tLongBlob",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "longblob"},
Raw: "longblob", Null: true},
},
{
Name: "tText",
Type: &schema.ColumnType{Type: &schema.StringType{T: "tinytext", Size: 0},
Raw: "tinytext", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_swedish_ci"},
},
},
{
Name: "tTinyText",
Type: &schema.ColumnType{Type: &schema.StringType{T: "tinytext", Size: 0},
Raw: "tinytext", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_swedish_ci"},
},
},
{
Name: "tMediumText",
Type: &schema.ColumnType{Type: &schema.StringType{T: "mediumtext", Size: 0},
Raw: "mediumtext", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_swedish_ci"},
},
},
{
Name: "tLongText",
Type: &schema.ColumnType{Type: &schema.StringType{T: "longtext", Size: 0},
Raw: "longtext", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_swedish_ci"},
},
},
{
Name: "tEnum",
Type: &schema.ColumnType{Type: &schema.EnumType{T: "enum", Values: []string{"a", "b"}},
Raw: "enum('a','b')", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_swedish_ci"},
},
},
{
Name: "tSet",
Type: &schema.ColumnType{Type: &mysql.SetType{Values: []string{"a", "b"}},
Raw: "set('a','b')", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_swedish_ci"},
},
},
{
Name: "tGeometry",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "geometry"},
Raw: "geometry", Null: true},
},
{
Name: "tPoint",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "point"},
Raw: "point", Null: true},
},
{
Name: "tMultiPoint",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "multipoint"},
Raw: "multipoint", Null: true},
},
{
Name: "tLineString",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "linestring"},
Raw: "linestring", Null: true},
},
{
Name: "tMultiLineString",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "multilinestring"},
Raw: "multilinestring", Null: true},
},
{
Name: "tPolygon",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "polygon"},
Raw: "polygon", Null: true},
},
{
Name: "tMultiPolygon",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "multipolygon"},
Raw: "multipolygon", Null: true},
},
{
Name: "tGeometryCollection",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: t.valueByVersion(
map[string]string{"mysql8": "geomcollection"}, "geometrycollection")},
Raw: t.valueByVersion(map[string]string{"mysql8": "geomcollection"},
"geometrycollection"), Null: true},
},
},
}
rmCreateStmt(ts)
require.EqualValues(t, &expected, ts)
t.hclDriftTest(n, realm, expected)
})
})
t.Run("JSON", func(t *testing.T) {
ddl := `
create table atlas_types_sanity
(
tJSON json default null
) CHARSET = latin1 COLLATE latin1_swedish_ci;
`
myRun(t, func(t *myTest) {
if t.version == "mysql56" {
return
}
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
require.Len(t, realm.Schemas, 1)
ts, ok := realm.Schemas[0].Table(n)
require.True(t, ok)
expected := schema.Table{
Name: n,
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_swedish_ci"},
&mysql.Engine{V: "InnoDB", Default: true},
},
Schema: realm.Schemas[0],
Columns: []*schema.Column{
func() *schema.Column {
c := &schema.Column{Name: "tJSON", Type: &schema.ColumnType{Type: &schema.JSONType{T: "json"}, Raw: "json", Null: true}}
switch t.version {
case "maria107":
c.Attrs = []schema.Attr{}
case "maria102", "maria103":
c.Type.Raw = "longtext"
c.Type.Type = &schema.StringType{T: "longtext"}
c.Attrs = []schema.Attr{
&schema.Charset{V: "utf8mb4"},
&schema.Collation{V: "utf8mb4_bin"},
}
}
return c
}(),
},
}
rmCreateStmt(ts)
require.EqualValues(t, &expected, ts)
})
})
t.Run("ImplicitIndexes", func(t *testing.T) {
myRun(t, func(t *myTest) {
testImplicitIndexes(t, t.db)
})
})
}
func (t *myTest) url(dbname string) string {
d := "mysql"
pass := ":pass"
if t.tidb() {
pass = ""
}
if t.mariadb() {
d = "mariadb"
}
return fmt.Sprintf("%s://root%s@localhost:%d/%s?parseTime=true", d, pass, t.port, dbname)
}
func (t *myTest) driver() migrate.Driver {
return t.drv
}
func (t *myTest) revisionsStorage() migrate.RevisionReadWriter {
return t.rrw
}
func (t *myTest) applyHcl(spec string) {
realm := t.loadRealm()
var desired schema.Schema
err := mysql.EvalHCLBytes([]byte(spec), &desired, nil)
require.NoError(t, err)
existing := realm.Schemas[0]
require.NoError(t, err)
diff, err := t.drv.SchemaDiff(existing, &desired)
require.NoError(t, err)
err = t.drv.ApplyChanges(context.Background(), diff)
require.NoError(t, err)
}
func (t *myTest) applyRealmHcl(spec string) {
realm := t.loadRealm()
var desired schema.Realm
err := mysql.EvalHCLBytes([]byte(spec), &desired, nil)
require.NoError(t, err)
diff, err := t.drv.RealmDiff(realm, &desired)
require.NoError(t, err)
err = t.drv.ApplyChanges(context.Background(), diff)
require.NoError(t, err)
}
func (t *myTest) diff(t1, t2 *schema.Table) []schema.Change {
changes, err := t.drv.TableDiff(t1, t2)
require.NoError(t, err)
return changes
}
func (t *myTest) migrate(changes ...schema.Change) {
err := t.drv.ApplyChanges(context.Background(), changes)
require.NoError(t, err)
}
func (t *myTest) dropTables(names ...string) {
t.Cleanup(func() {
_, err := t.db.Exec("DROP TABLE IF EXISTS " + strings.Join(names, ", "))
require.NoError(t.T, err, "drop tables %q", names)
})
}
func (t *myTest) dropSchemas(names ...string) {
t.Cleanup(func() {
for _, n := range names {
_, err := t.db.Exec("DROP DATABASE IF EXISTS " + n)
require.NoError(t.T, err, "drop db %q", names)
}
})
}
func (t *myTest) realm() *schema.Realm {
r := &schema.Realm{
Schemas: []*schema.Schema{
{
Name: "test",
Attrs: t.defaultAttrs(),
},
},
Attrs: t.defaultAttrs(),
}
r.Schemas[0].Realm = r
return r
}
func (t *myTest) users() *schema.Table {
usersT := &schema.Table{
Name: "users",
Schema: t.realm().Schemas[0],
Columns: []*schema.Column{
{
Name: "id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}},
Attrs: []schema.Attr{&mysql.AutoIncrement{}},
},
{
Name: "x",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}},
},
},
Attrs: t.defaultAttrs(),
}
usersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}
return usersT
}
func (t *myTest) posts() *schema.Table {
usersT := t.users()
postsT := &schema.Table{
Name: "posts",
Schema: t.realm().Schemas[0],
Columns: []*schema.Column{
{
Name: "id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}},
Attrs: []schema.Attr{&mysql.AutoIncrement{}},
},
{
Name: "author_id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.RawExpr{X: "10"},
},
{
Name: "ctime",
Type: &schema.ColumnType{Raw: "timestamp", Type: &schema.TimeType{T: "timestamp"}},
Default: &schema.RawExpr{
X: "CURRENT_TIMESTAMP",
},
Attrs: []schema.Attr{
&mysql.OnUpdate{
A: "CURRENT_TIMESTAMP",
},
},
},
},
Attrs: t.defaultAttrs(),
}
postsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}
postsT.Indexes = []*schema.Index{
{Name: "author_id", Parts: []*schema.IndexPart{{C: postsT.Columns[1]}}},
{Name: "id_author_id_unique", Unique: true, Parts: []*schema.IndexPart{{C: postsT.Columns[1]}, {C: postsT.Columns[0]}}},
}
postsT.ForeignKeys = []*schema.ForeignKey{
{Symbol: "author_id", Table: postsT, Columns: postsT.Columns[1:2], RefTable: usersT, RefColumns: usersT.Columns[:1], OnDelete: schema.NoAction},
}
return postsT
}
func (t *myTest) valueByVersion(values map[string]string, defaults string) string {
if v, ok := values[t.version]; ok {
return v
}
return defaults
}
func (t *myTest) intByVersion(values map[string]int, defaults int) int {
if v, ok := values[t.version]; ok {
return v
}
return defaults
}
func (t *myTest) quoted(s string) string {
c := "\""
if t.mariadb() {
c = "'"
}
return c + s + c
}
func (t *myTest) loadRealm() *schema.Realm {
r, err := t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{
Schemas: []string{"test"},
Mode: schema.InspectSchemas | schema.InspectTables,
})
require.NoError(t, err)
return r
}
func (t *myTest) loadUsers() *schema.Table {
return t.loadTable("users")
}
func (t *myTest) loadPosts() *schema.Table {
return t.loadTable("posts")
}
func (t *myTest) loadTable(name string) *schema.Table {
realm := t.loadRealm()
require.Len(t, realm.Schemas, 1)
table, ok := realm.Schemas[0].Table(name)
require.True(t, ok)
return table
}
func (t *myTest) mariadb() bool { return strings.HasPrefix(t.version, "maria") }
func (t *myTest) tidb() bool { return strings.HasPrefix(t.version, "tidb") }
// defaultConfig returns the default charset and
// collation configuration based on the MySQL version.
func (t *myTest) defaultAttrs() []schema.Attr {
var (
charset = "latin1"
collation = "latin1_swedish_ci"
)
switch {
case strings.Contains(t.version, "tidb"):
charset = "utf8mb4"
collation = "utf8mb4_bin"
case t.version == "mysql8":
charset = "utf8mb4"
collation = "utf8mb4_0900_ai_ci"
case t.version == "maria107":
charset = "utf8mb4"
collation = "utf8mb4_general_ci"
}
return []schema.Attr{
&schema.Charset{
V: charset,
},
&schema.Collation{
V: collation,
},
}
}
func (t *myTest) hclDriftTest(n string, realm *schema.Realm, expected schema.Table) {
spec, err := mysql.MarshalHCL(realm.Schemas[0])
require.NoError(t, err)
t.dropTables(n)
t.applyHcl(string(spec))
realm = t.loadRealm()
require.Len(t, realm.Schemas, 1)
ts, ok := realm.Schemas[0].Table(n)
require.True(t, ok)
rmCreateStmt(ts)
require.EqualValues(t, &expected, ts)
}
func rmCreateStmt(t *schema.Table) {
for i := range t.Attrs {
if _, ok := t.Attrs[i].(*mysql.CreateStmt); ok {
t.Attrs = append(t.Attrs[:i], t.Attrs[i+1:]...)
return
}
}
}
func intp(i int) *int { return &i }
================================================
FILE: internal/integration/postgres_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package integration
import (
"context"
"database/sql"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"testing"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/postgres"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
_ "github.com/lib/pq"
"github.com/stretchr/testify/require"
)
type pgTest struct {
*testing.T
db *sql.DB
drv migrate.Driver
rrw migrate.RevisionReadWriter
version string
port int
once sync.Once
}
var pgTests = map[string]*pgTest{
"postgres-ext-postgis": {port: 5429},
"postgres10": {port: 5430},
"postgres11": {port: 5431},
"postgres12": {port: 5432},
"postgres13": {port: 5433},
"postgres14": {port: 5434},
"postgres15": {port: 5435},
}
func pgRun(t *testing.T, fn func(*pgTest)) {
for version, tt := range pgTests {
if flagVersion == "" || flagVersion == version {
t.Run(version, func(t *testing.T) {
tt.once.Do(func() {
var err error
tt.version = version
tt.rrw = &rrw{}
tt.db, err = sql.Open("postgres", fmt.Sprintf("host=localhost port=%d user=postgres dbname=test password=pass sslmode=disable", tt.port))
if err != nil {
log.Fatalln(err)
}
dbs = append(dbs, tt.db) // close connection after all tests have been run
// the postgis/postgis image enables the postgis_topology and postgis_tiger_geocoder extensions,
// this creates a few unwanted schemas, so we drop it.
// https://github.com/postgis/docker-postgis/issues/187
if tt.version == "postgres-ext-postgis" {
schemasToDrop := []string{
"tiger", // created by postgis_tiger_geocoder
"tiger_data", // created by postgis_tiger_geocoder
"topology", // created by postgis_topology
}
for _, s := range schemasToDrop {
if _, err := tt.db.Exec("DROP SCHEMA IF EXISTS " + s + " CASCADE;"); err != nil {
log.Fatalf("error dropping schema %q: %v", s, err)
}
}
}
tt.drv, err = postgres.Open(tt.db)
if err != nil {
log.Fatalln(err)
}
})
tt := &pgTest{T: t, db: tt.db, drv: tt.drv, version: version, port: tt.port, rrw: tt.rrw}
fn(tt)
})
}
}
}
func TestPostgres_Executor(t *testing.T) {
pgRun(t, func(t *pgTest) {
testExecutor(t)
})
}
func TestPostgres_AddDropTable(t *testing.T) {
pgRun(t, func(t *pgTest) {
testAddDrop(t)
})
}
func TestPostgres_Relation(t *testing.T) {
pgRun(t, func(t *pgTest) {
testRelation(t)
})
}
func TestPostgres_NoSchema(t *testing.T) {
pgRun(t, func(t *pgTest) {
t.Cleanup(func() {
_, err := t.db.Exec("CREATE SCHEMA IF NOT EXISTS public")
require.NoError(t, err)
})
_, err := t.db.Exec("DROP SCHEMA IF EXISTS public CASCADE")
require.NoError(t, err)
r, err := t.drv.InspectRealm(context.Background(), nil)
require.NoError(t, err)
require.Nil(t, r.Schemas)
})
}
func TestPostgres_AddIndexedColumns(t *testing.T) {
pgRun(t, func(t *pgTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
usersT.Columns = append(usersT.Columns, &schema.Column{
Name: "a",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.Literal{V: "10"},
}, &schema.Column{
Name: "b",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.Literal{V: "10"},
}, &schema.Column{
Name: "c",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.Literal{V: "10"},
})
parts := usersT.Columns[len(usersT.Columns)-3:]
usersT.Indexes = append(usersT.Indexes, &schema.Index{
Unique: true,
Name: "a_b_c_unique",
Parts: []*schema.IndexPart{{C: parts[0]}, {C: parts[1]}, {C: parts[2]}},
})
changes := t.diff(t.loadUsers(), usersT)
require.NotEmpty(t, changes, "usersT contains 3 new columns and 1 new index")
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// Dropping a column involves in a multi-column
// index causes the index to be dropped as well.
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
changes = t.diff(t.loadUsers(), usersT)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, t.loadUsers())
usersT = t.loadUsers()
_, ok := usersT.Index("a_b_c_unique")
require.False(t, ok)
})
}
func TestPostgres_ColumnCheck(t *testing.T) {
pgRun(t, func(t *pgTest) {
usersT := &schema.Table{
Name: "users",
Attrs: []schema.Attr{schema.NewCheck().SetName("users_c_check").SetExpr("c > 5")},
Columns: []*schema.Column{
{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}},
{Name: "c", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}},
},
}
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
ensureNoChange(t, usersT)
})
}
func TestPostgres_AddColumns(t *testing.T) {
pgRun(t, func(t *pgTest) {
usersT := t.users()
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
_, err := t.db.Exec("CREATE EXTENSION IF NOT EXISTS hstore")
require.NoError(t, err)
usersT.Columns = append(
usersT.Columns,
&schema.Column{Name: "a", Type: &schema.ColumnType{Type: &schema.BinaryType{T: "bytea"}}},
&schema.Column{Name: "b", Type: &schema.ColumnType{Type: &schema.FloatType{T: "double precision", Precision: 10}}, Default: &schema.Literal{V: "10.1"}},
&schema.Column{Name: "c", Type: &schema.ColumnType{Type: &schema.StringType{T: "character"}}, Default: &schema.Literal{V: "'y'"}},
&schema.Column{Name: "d", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 10, Scale: 2}}, Default: &schema.Literal{V: "0.99"}},
&schema.Column{Name: "e", Type: &schema.ColumnType{Type: &schema.JSONType{T: "json"}}, Default: &schema.Literal{V: "'{}'"}},
&schema.Column{Name: "f", Type: &schema.ColumnType{Type: &schema.JSONType{T: "jsonb"}}, Default: &schema.Literal{V: "'1'"}},
&schema.Column{Name: "g", Type: &schema.ColumnType{Type: &schema.FloatType{T: "float", Precision: 10}}, Default: &schema.Literal{V: "'1'"}},
&schema.Column{Name: "h", Type: &schema.ColumnType{Type: &schema.FloatType{T: "float", Precision: 30}}, Default: &schema.Literal{V: "'1'"}},
&schema.Column{Name: "i", Type: &schema.ColumnType{Type: &schema.FloatType{T: "float", Precision: 53}}, Default: &schema.Literal{V: "1"}},
&schema.Column{Name: "j", Type: &schema.ColumnType{Type: &postgres.SerialType{T: "serial"}}},
&schema.Column{Name: "k", Type: &schema.ColumnType{Type: &postgres.CurrencyType{T: "money"}}, Default: &schema.Literal{V: "'100'"}},
&schema.Column{Name: "l", Type: &schema.ColumnType{Type: &postgres.CurrencyType{T: "money"}, Null: true}, Default: &schema.RawExpr{X: "'52093.89'::money"}},
&schema.Column{Name: "m", Type: &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}, Null: true}, Default: &schema.Literal{V: "false"}},
&schema.Column{Name: "n", Type: &schema.ColumnType{Type: &schema.SpatialType{T: "point"}, Null: true}, Default: &schema.Literal{V: "'(1,2)'"}},
&schema.Column{Name: "o", Type: &schema.ColumnType{Type: &schema.SpatialType{T: "line"}, Null: true}, Default: &schema.Literal{V: "'{1,2,3}'"}},
&schema.Column{Name: "p", Type: &schema.ColumnType{Type: &postgres.UserDefinedType{T: "hstore"}, Null: true}, Default: &schema.RawExpr{X: "'a => 1'"}},
&schema.Column{Name: "q", Type: &schema.ColumnType{Type: &postgres.ArrayType{Type: &schema.StringType{T: "text"}, T: "text[]"}, Null: true}, Default: &schema.Literal{V: "'{}'"}},
)
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 17)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
}
func TestPostgres_ColumnInt(t *testing.T) {
ctx := context.Background()
run := func(t *testing.T, change func(*schema.Column)) {
pgRun(t, func(t *pgTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}}}},
}
err := t.drv.ApplyChanges(ctx, []schema.Change{&schema.AddTable{T: usersT}})
require.NoError(t, err)
t.dropTables(usersT.Name)
change(usersT.Columns[0])
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
}
t.Run("ChangeNull", func(t *testing.T) {
run(t, func(c *schema.Column) {
c.Type.Null = true
})
})
t.Run("ChangeType", func(t *testing.T) {
run(t, func(c *schema.Column) {
c.Type.Type.(*schema.IntegerType).T = "integer"
})
})
t.Run("ChangeDefault", func(t *testing.T) {
run(t, func(c *schema.Column) {
c.Default = &schema.RawExpr{X: "0"}
})
})
}
func TestPostgres_ColumnArray(t *testing.T) {
pgRun(t, func(t *pgTest) {
usersT := t.users()
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
// Add column.
usersT.Columns = append(
usersT.Columns,
&schema.Column{Name: "a", Type: &schema.ColumnType{Raw: "int[]", Type: &postgres.ArrayType{Type: &schema.IntegerType{T: "int"}, T: "int[]"}}, Default: &schema.Literal{V: "'{1}'"}},
)
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// Check default.
usersT.Columns[2].Default = &schema.RawExpr{X: "ARRAY[1]"}
ensureNoChange(t, usersT)
// Change default.
usersT.Columns[2].Default = &schema.RawExpr{X: "ARRAY[1,2]"}
changes = t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
}
func TestPostgres_Enums(t *testing.T) {
pgRun(t, func(t *pgTest) {
ctx := context.Background()
usersT := &schema.Table{
Name: "users",
Schema: t.realm().Schemas[0],
Columns: []*schema.Column{
{Name: "state", Type: &schema.ColumnType{Type: &schema.EnumType{T: "state", Values: []string{"on", "off"}}}},
},
}
t.Cleanup(func() {
_, err := t.drv.ExecContext(ctx, "DROP TYPE IF EXISTS state, day")
require.NoError(t, err)
})
// Create table with an enum column.
err := t.drv.ApplyChanges(ctx, []schema.Change{
&schema.AddObject{O: &schema.EnumType{T: "state", Values: []string{"on", "off"}, Schema: usersT.Schema}},
&schema.AddTable{T: usersT},
})
require.NoError(t, err, "create a new table with an enum column")
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
// Add another enum column.
usersT.Columns = append(
usersT.Columns,
&schema.Column{Name: "day", Type: &schema.ColumnType{Type: &schema.EnumType{T: "day", Values: []string{"sunday", "monday"}}}},
)
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
err = t.drv.ApplyChanges(ctx, []schema.Change{
&schema.AddObject{O: &schema.EnumType{T: "day", Values: []string{"sunday", "monday"}, Schema: usersT.Schema}},
&schema.ModifyTable{T: usersT, Changes: changes},
})
require.NoError(t, err, "add a new enum column to existing table")
ensureNoChange(t, usersT)
})
}
func TestPostgres_ForeignKey(t *testing.T) {
t.Run("ChangeAction", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
usersT, postsT := t.users(), t.posts()
t.dropTables(postsT.Name, usersT.Name)
t.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})
ensureNoChange(t, postsT, usersT)
postsT = t.loadPosts()
fk, ok := postsT.ForeignKey("author_id")
require.True(t, ok)
fk.OnUpdate = schema.SetNull
fk.OnDelete = schema.Cascade
changes := t.diff(t.loadPosts(), postsT)
require.Len(t, changes, 1)
modifyF, ok := changes[0].(*schema.ModifyForeignKey)
require.True(t, ok)
require.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)
t.migrate(&schema.ModifyTable{T: postsT, Changes: changes})
ensureNoChange(t, postsT, usersT)
})
})
t.Run("UnsetNull", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
usersT, postsT := t.users(), t.posts()
t.dropTables(postsT.Name, usersT.Name)
fk, ok := postsT.ForeignKey("author_id")
require.True(t, ok)
fk.OnDelete = schema.SetNull
fk.OnUpdate = schema.SetNull
t.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})
ensureNoChange(t, postsT, usersT)
postsT = t.loadPosts()
c, ok := postsT.Column("author_id")
require.True(t, ok)
c.Type.Null = false
fk, ok = postsT.ForeignKey("author_id")
require.True(t, ok)
fk.OnUpdate = schema.NoAction
fk.OnDelete = schema.NoAction
changes := t.diff(t.loadPosts(), postsT)
require.Len(t, changes, 2)
modifyC, ok := changes[0].(*schema.ModifyColumn)
require.True(t, ok)
require.True(t, modifyC.Change == schema.ChangeNull)
modifyF, ok := changes[1].(*schema.ModifyForeignKey)
require.True(t, ok)
require.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)
t.migrate(&schema.ModifyTable{T: postsT, Changes: changes})
ensureNoChange(t, postsT, usersT)
})
})
t.Run("AddDrop", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
usersT := t.users()
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
ensureNoChange(t, usersT)
// Add foreign key.
usersT.Columns = append(usersT.Columns, &schema.Column{
Name: "spouse_id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
})
usersT.ForeignKeys = append(usersT.ForeignKeys, &schema.ForeignKey{
Symbol: "spouse_id",
Table: usersT,
Columns: usersT.Columns[len(usersT.Columns)-1:],
RefTable: usersT,
RefColumns: usersT.Columns[:1],
OnDelete: schema.NoAction,
})
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
addC, ok := changes[0].(*schema.AddColumn)
require.True(t, ok)
require.Equal(t, "spouse_id", addC.C.Name)
addF, ok := changes[1].(*schema.AddForeignKey)
require.True(t, ok)
require.Equal(t, "spouse_id", addF.F.Symbol)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// Drop foreign keys.
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
usersT.ForeignKeys = usersT.ForeignKeys[:len(usersT.ForeignKeys)-1]
changes = t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
})
}
func TestPostgres_EntGlobalUniqueID(t *testing.T) {
// Migration to global unique identifiers.
pgRun(t, func(t *pgTest) {
ctx := context.Background()
t.dropTables("global_id")
_, err := t.driver().ExecContext(ctx, "CREATE TABLE global_id (id int NOT NULL GENERATED BY DEFAULT AS IDENTITY, PRIMARY KEY(id))")
require.NoError(t, err)
_, err = t.driver().ExecContext(ctx, "ALTER TABLE global_id ALTER COLUMN id RESTART WITH 1024")
require.NoError(t, err)
_, err = t.driver().ExecContext(ctx, "INSERT INTO global_id VALUES (default), (default)")
require.NoError(t, err)
var id int
require.NoError(t, t.db.QueryRow("SELECT id FROM global_id").Scan(&id))
require.Equal(t, 1024, id)
_, err = t.driver().ExecContext(ctx, "DELETE FROM global_id WHERE id = 1024")
require.NoError(t, err)
globalT := t.loadTable("global_id")
c, ok := globalT.Column("id")
require.True(t, ok)
require.EqualValues(t, 1, c.Attrs[0].(*postgres.Identity).Sequence.Start)
t.migrate(&schema.ModifyTable{
T: globalT,
Changes: []schema.Change{
&schema.ModifyColumn{
From: globalT.Columns[0],
To: schema.NewIntColumn("id", "int").
AddAttrs(&postgres.Identity{
Generation: "BY DEFAULT",
Sequence: &postgres.Sequence{
Start: 1024,
},
}),
Change: schema.ChangeAttr,
},
},
})
_, err = t.driver().ExecContext(ctx, "INSERT INTO global_id VALUES (default), (default)")
require.NoError(t, err)
globalT = t.loadTable("global_id")
c, ok = globalT.Column("id")
require.True(t, ok)
require.EqualValues(t, 1024, c.Attrs[0].(*postgres.Identity).Sequence.Start)
})
}
func TestPostgres_AdvisoryLock(t *testing.T) {
pgRun(t, func(t *pgTest) {
testAdvisoryLock(t.T, t.drv.(schema.Locker))
})
}
func TestPostgres_HCL(t *testing.T) {
full := `
schema "public" {
}
table "users" {
schema = schema.public
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
table "posts" {
schema = schema.public
column "id" {
type = int
}
column "tags" {
type = sql("text[]")
}
column "author_id" {
type = int
}
foreign_key "author" {
columns = [
table.posts.column.author_id,
]
ref_columns = [
table.users.column.id,
]
}
primary_key {
columns = [table.users.column.id]
}
}
`
empty := `
schema "public" {
}
`
pgRun(t, func(t *pgTest) {
testHCLIntegration(t, full, empty)
})
}
func TestPostgres_HCL_Realm(t *testing.T) {
pgRun(t, func(t *pgTest) {
t.dropSchemas("second")
realm := t.loadRealm()
hcl, err := postgres.MarshalHCL(realm)
require.NoError(t, err)
wa := string(hcl) + `
schema "second" {
comment = "second schema"
}
`
t.applyRealmHcl(wa)
realm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{})
require.NoError(t, err)
_, ok := realm.Schema("public")
require.True(t, ok)
s2, ok := realm.Schema("second")
require.True(t, ok)
require.Len(t, s2.Attrs, 1)
require.Equal(t, "second schema", s2.Attrs[0].(*schema.Comment).Text)
})
}
func TestPostgres_HCL_ForeignKeyCrossSchema(t *testing.T) {
const expected = `table "credit_cards" {
schema = schema.financial
column "id" {
null = false
type = serial
}
column "user_id" {
null = false
type = integer
}
primary_key {
columns = [column.id]
}
foreign_key "user_id_fkey" {
columns = [column.user_id]
ref_columns = [table.users.users.column.id]
on_update = NO_ACTION
on_delete = NO_ACTION
}
}
table "financial" "t" {
schema = schema.financial
column "t_id" {
null = false
type = uuid
}
primary_key {
columns = [column.t_id]
}
foreign_key "fk_t_id" {
columns = [column.t_id]
ref_columns = [table.users.t.column.id]
on_update = NO_ACTION
on_delete = NO_ACTION
}
}
table "financial" "users" {
schema = schema.financial
column "id" {
null = false
type = serial
}
}
table "users" "t" {
schema = schema.users
column "id" {
null = false
type = uuid
}
primary_key {
columns = [column.id]
}
}
table "users" "users" {
schema = schema.users
column "id" {
null = false
type = bigserial
}
column "email" {
null = false
type = character_varying
}
primary_key {
columns = [column.id]
}
}
schema "financial" {
}
schema "users" {
}
`
pgRun(t, func(t *pgTest) {
t.dropSchemas("financial", "users")
realm := t.loadRealm()
hcl, err := postgres.MarshalHCL(realm)
require.NoError(t, err)
t.applyRealmHcl(string(hcl) + "\n" + expected)
realm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{Schemas: []string{"users", "financial"}})
require.NoError(t, err)
actual, err := postgres.MarshalHCL(realm)
require.NoError(t, err)
require.Equal(t, expected, string(actual))
})
}
func (t *pgTest) applyRealmHcl(spec string) {
realm := t.loadRealm()
var desired schema.Realm
err := postgres.EvalHCLBytes([]byte(spec), &desired, nil)
require.NoError(t, err)
diff, err := t.drv.RealmDiff(realm, &desired)
require.NoError(t, err)
err = t.drv.ApplyChanges(context.Background(), diff)
require.NoError(t, err)
}
func TestPostgres_Snapshot(t *testing.T) {
pgRun(t, func(t *pgTest) {
client, err := sqlclient.Open(context.Background(), fmt.Sprintf("postgres://postgres:pass@localhost:%d/test?sslmode=disable&search_path=another", t.port))
require.NoError(t, err)
_, err = client.ExecContext(context.Background(), "CREATE SCHEMA another")
require.NoError(t, err)
t.Cleanup(func() {
_, err = client.ExecContext(context.Background(), "DROP SCHEMA IF EXISTS another")
require.NoError(t, client.Close())
})
drv := client.Driver
_, err = t.driver().Snapshot(context.Background())
require.ErrorAs(t, err, new(*migrate.NotCleanError))
r, err := drv.InspectRealm(context.Background(), nil)
require.NoError(t, err)
restore, err := drv.Snapshot(context.Background())
require.NoError(t, err) // connected to test schema
require.NoError(t, drv.ApplyChanges(context.Background(), []schema.Change{
&schema.AddTable{T: schema.NewTable("my_table").
AddColumns(
schema.NewIntColumn("col_1", "integer").SetNull(true),
schema.NewIntColumn("col_2", "bigint"),
),
},
}))
t.Cleanup(func() {
t.dropTables("my_table")
})
require.NoError(t, restore(context.Background()))
r1, err := drv.InspectRealm(context.Background(), nil)
require.NoError(t, err)
diff, err := drv.RealmDiff(r1, r)
require.NoError(t, err)
require.Zero(t, diff)
})
}
func TestPostgres_CLI_MigrateApplyBC(t *testing.T) {
pgRun(t, func(t *pgTest) {
testCLIMigrateApplyBC(t, "postgres")
})
}
func TestPostgres_CLI(t *testing.T) {
h := `
schema "public" {
}
table "users" {
schema = schema.public
column "id" {
type = integer
}
primary_key {
columns = [table.users.column.id]
}
}`
t.Run("SchemaInspect", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
testCLISchemaInspect(t, h, t.url(""), postgres.EvalHCL)
})
})
t.Run("SchemaApply", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
testCLISchemaApply(t, h, t.url(""))
})
})
t.Run("SchemaApplyDryRun", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
testCLISchemaApplyDry(t, h, t.url(""))
})
})
t.Run("SchemaApplyWithVars", func(t *testing.T) {
h := `
variable "tenant" {
type = string
}
schema "tenant" {
name = var.tenant
}
table "users" {
schema = schema.tenant
column "id" {
type = int
}
}
`
pgRun(t, func(t *pgTest) {
testCLISchemaApply(t, h, t.url(""), "--var", "tenant=public")
})
})
t.Run("SchemaDiffRun", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
testCLISchemaDiff(t, t.url(""))
})
})
t.Run("SchemaApplyAutoApprove", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
testCLISchemaApplyAutoApprove(t, h, t.url(""))
})
})
t.Run("SchemaApplyFromMigrationDir", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
testCLISchemaApplyFromMigrationDir(t)
})
})
}
func TestPostgres_MigrateApply(t *testing.T) {
var (
bin = cliPath(t)
ctx = context.Background()
)
pgRun(t, func(t *pgTest) {
_, err := t.db.ExecContext(ctx, "DROP DATABASE IF EXISTS migrate_apply")
require.NoError(t, err)
_, err = t.db.ExecContext(ctx, "CREATE DATABASE migrate_apply")
require.NoError(t, err)
p := t.TempDir()
require.NoError(t, os.WriteFile(filepath.Join(p, "1.sql"), []byte(`
CREATE SCHEMA IF NOT EXISTS public;
CREATE TABLE public.users (id int);
`), 0644))
require.NoError(t, exec.Command(bin, "migrate", "hash", "--dir", "file://"+p).Run())
out, err := exec.Command(
bin, "migrate", "apply",
"--dir", "file://"+p,
"--url", t.dbURL("migrate_apply", "public"),
).CombinedOutput()
require.NoError(t, err)
require.Regexp(t, `Migrating to version 1 \(1 migrations in total\):
-- migrating version 1
-> CREATE SCHEMA IF NOT EXISTS public;
-> CREATE TABLE public.users \(id int\);
-- ok \(.+\)
-------------------------
-- .+
-- 1 migration
-- 2 sql statements
`, string(out))
out, err = exec.Command(
bin, "migrate", "apply",
"--dir", "file://"+p,
"--url", t.dbURL("migrate_apply", "public"),
).CombinedOutput()
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", string(out))
out, err = exec.Command(
bin, "schema", "inspect",
"--url", t.dbURL("migrate_apply", "public"),
"--format", "{{ range $s := .Realm.Schemas }}{{ range .Tables }}{{ $s.Name }}-{{ .Name }},{{ end }}{{ end }}",
).CombinedOutput()
require.NoError(t, err)
require.Equal(t, "public-atlas_schema_revisions,public-users,", string(out), "tables reside on the same public schema")
// Database-scope migration, default to atlas_schema_revisions.
_, err = exec.Command(
bin, "schema", "clean",
"--url", t.dbURL("migrate_apply", ""),
"--auto-approve",
).CombinedOutput()
require.NoError(t, err)
out, err = exec.Command(
bin, "migrate", "apply",
"--dir", "file://"+p,
"--url", t.dbURL("migrate_apply", ""),
).CombinedOutput()
require.NoError(t, err)
require.Regexp(t, `Migrating to version 1 \(1 migrations in total\):
-- migrating version 1
-> CREATE SCHEMA IF NOT EXISTS public;
-> CREATE TABLE public.users \(id int\);
-- ok \(.+\)
-------------------------
-- .+
-- 1 migration
-- 2 sql statements
`, string(out))
out, err = exec.Command(
bin, "migrate", "apply",
"--dir", "file://"+p,
"--url", t.dbURL("migrate_apply", ""),
).CombinedOutput()
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", string(out))
out, err = exec.Command(
bin, "schema", "inspect",
"--url", t.dbURL("migrate_apply", ""),
"--format", "{{ range $s := .Realm.Schemas }}{{ range .Tables }}{{ $s.Name }}-{{ .Name }},{{ end }}{{ end }}",
).CombinedOutput()
require.NoError(t, err)
require.Equal(t, "atlas_schema_revisions-atlas_schema_revisions,public-users,", string(out), "revisions table should reside in atlas_schema_revisions")
// Custom schema-revisions schema.
_, err = exec.Command(
bin, "schema", "clean",
"--url", t.dbURL("migrate_apply", ""),
"--auto-approve",
).CombinedOutput()
require.NoError(t, err)
out, err = exec.Command(
bin, "migrate", "apply",
"--dir", "file://"+p,
"--url", t.dbURL("migrate_apply", ""),
"--revisions-schema", "mashraki",
).CombinedOutput()
require.NoError(t, err)
require.Regexp(t, `Migrating to version 1 \(1 migrations in total\):
-- migrating version 1
-> CREATE SCHEMA IF NOT EXISTS public;
-> CREATE TABLE public.users \(id int\);
-- ok \(.+\)
-------------------------
-- .+
-- 1 migration
-- 2 sql statements
`, string(out))
out, err = exec.Command(
bin, "migrate", "apply",
"--dir", "file://"+p,
"--url", t.dbURL("migrate_apply", ""),
"--revisions-schema", "mashraki",
).CombinedOutput()
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", string(out))
out, err = exec.Command(
bin, "schema", "inspect",
"--url", t.dbURL("migrate_apply", ""),
"--format", "{{ range $s := .Realm.Schemas }}{{ range .Tables }}{{ $s.Name }}-{{ .Name }},{{ end }}{{ end }}",
).CombinedOutput()
require.NoError(t, err)
require.Equal(t, "mashraki-atlas_schema_revisions,public-users,", string(out), "revisions table should reside in atlas_schema_revisions")
})
}
func TestPostgres_CLI_MultiSchema(t *testing.T) {
h := `
schema "public" {
}
table "users" {
schema = schema.public
column "id" {
type = integer
}
primary_key {
columns = [column.id]
}
}
schema "test2" {
}
table "pets" {
schema = schema.test2
column "id" {
type = integer
}
column "owner_id" {
type = integer
}
primary_key {
columns = [column.id]
}
foreign_key "owner_id" {
columns = [column.owner_id]
ref_columns = [table.users.column.id]
on_delete = NO_ACTION
on_update = NO_ACTION
}
}`
t.Run("SchemaInspect", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
t.dropTables("users")
t.dropSchemas("test2")
testCLIMultiSchemaInspect(t, h, t.url(""), []string{"public", "test2"}, postgres.EvalHCL)
})
})
t.Run("SchemaApply", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
t.dropTables("users")
t.dropSchemas("test2")
testCLIMultiSchemaApply(t, h, t.url(""), []string{"public", "test2"}, postgres.EvalHCL)
})
})
}
func TestPostgres_NormalizeRealm(t *testing.T) {
bin := cliPath(t)
pgRun(t, func(t *pgTest) {
dir := t.TempDir()
_, err := t.db.Exec("CREATE DATABASE normalized_realm")
require.NoError(t, err)
defer t.db.Exec("DROP DATABASE IF EXISTS normalized_realm")
hcl := `
schema "public" {}
enum "status" {
schema = schema.public
values = ["active", "inactive"]
}
table "users" {
schema = schema.public
column "id" { type = serial }
column "e" { type = enum.status }
column "ae" { type = sql("public.status[]") }
}
schema "other" {}
table "posts" {
schema = schema.other
column "id" { type = integer }
}
table "with_default" {
schema = schema.other
column "name" {
type = varchar
default = sql("lower('Hello')")
}
}
`
err = os.WriteFile(filepath.Join(dir, "schema.hcl"), []byte(hcl), 0600)
require.NoError(t, err)
out, err := exec.Command(
bin, "schema", "inspect",
"--url", fmt.Sprintf("file://%s", filepath.Join(dir, "schema.hcl")),
"--dev-url", fmt.Sprintf("postgres://postgres:pass@localhost:%d/normalized_realm?sslmode=disable", t.port),
).CombinedOutput()
require.NoError(t, err)
require.Equal(t, `table "posts" {
schema = schema.other
column "id" {
null = false
type = integer
}
}
table "with_default" {
schema = schema.other
column "name" {
null = false
type = character_varying
default = sql("lower('Hello'::text)")
}
}
table "users" {
schema = schema.public
column "id" {
null = false
type = serial
}
column "e" {
null = false
type = enum.status
}
column "ae" {
null = false
type = sql("public.status[]")
}
}
enum "status" {
schema = schema.public
values = ["active", "inactive"]
}
schema "other" {
}
schema "public" {
comment = "standard public schema"
}
`, string(out))
err = t.drv.CheckClean(context.Background(), nil)
require.NoError(t, err)
})
}
func TestPostgres_MigrateDiffRealm(t *testing.T) {
bin := cliPath(t)
pgRun(t, func(t *pgTest) {
dir := t.TempDir()
_, err := t.db.Exec("CREATE DATABASE migrate_diff")
require.NoError(t, err)
defer t.db.Exec("DROP DATABASE IF EXISTS migrate_diff")
hcl := `
schema "public" {}
table "users" {
schema = schema.public
column "id" { type = integer }
}
schema "other" {}
table "posts" {
schema = schema.other
column "id" { type = integer }
}
`
err = os.WriteFile(filepath.Join(dir, "schema.hcl"), []byte(hcl), 0600)
diff := func(name string) string {
out, err := exec.Command(
bin, "migrate", "diff", name,
"--dir", fmt.Sprintf("file://%s", filepath.Join(dir, "migrations")),
"--to", fmt.Sprintf("file://%s", filepath.Join(dir, "schema.hcl")),
"--dev-url", fmt.Sprintf("postgres://postgres:pass@localhost:%d/migrate_diff?sslmode=disable", t.port),
).CombinedOutput()
require.NoError(t, err, string(out))
return strings.TrimSpace(string(out))
}
require.Empty(t, diff("initial"))
// Expect one file and read its contents.
files, err := os.ReadDir(filepath.Join(dir, "migrations"))
require.NoError(t, err)
require.Equal(t, 2, len(files))
require.Equal(t, "atlas.sum", files[1].Name())
b, err := os.ReadFile(filepath.Join(dir, "migrations", files[0].Name()))
require.NoError(t, err)
require.Equal(t,
`-- Add new schema named "other"
CREATE SCHEMA "other";
-- Create "users" table
CREATE TABLE "public"."users" ("id" integer NOT NULL);
-- Create "posts" table
CREATE TABLE "other"."posts" ("id" integer NOT NULL);
`, string(b))
require.Equal(t, "The migration directory is synced with the desired state, no changes to be made", diff("no_change"))
// Append a change to the schema and expect a migration to be created.
hcl += `
table "other" "users" {
schema = schema.other
column "id" { type = integer }
}`
err = os.WriteFile(filepath.Join(dir, "schema.hcl"), []byte(hcl), 0600)
require.Empty(t, diff("second"))
require.Equal(t, "The migration directory is synced with the desired state, no changes to be made", diff("no_change"))
files, err = os.ReadDir(filepath.Join(dir, "migrations"))
require.NoError(t, err)
require.Equal(t, 3, len(files), dir)
b, err = os.ReadFile(filepath.Join(dir, "migrations", files[1].Name()))
require.NoError(t, err)
require.Equal(t,
`-- Create "users" table
CREATE TABLE "other"."users" ("id" integer NOT NULL);
`, string(b))
})
}
func TestPostgres_SchemaDiff(t *testing.T) {
bin := cliPath(t)
pgRun(t, func(t *pgTest) {
dir := t.TempDir()
_, err := t.db.Exec("CREATE DATABASE test1")
require.NoError(t, err)
t.Cleanup(func() {
_, err := t.db.Exec("DROP DATABASE IF EXISTS test1")
require.NoError(t, err)
})
_, err = t.db.Exec("CREATE DATABASE test2")
require.NoError(t, err)
t.Cleanup(func() {
_, err = t.db.Exec("DROP DATABASE IF EXISTS test2")
require.NoError(t, err)
})
diff := func(db1, db2 string) string {
out, err := exec.Command(
bin, "schema", "diff",
"--from", fmt.Sprintf("postgres://postgres:pass@localhost:%d/%s", t.port, db1),
"--to", fmt.Sprintf("postgres://postgres:pass@localhost:%d/%s", t.port, db2),
).CombinedOutput()
require.NoError(t, err, string(out))
return strings.TrimSpace(string(out))
}
// Diff a database with itself.
require.Equal(t, "Schemas are synced, no changes to be made.", diff("test1?sslmode=disable", "test2?sslmode=disable"))
// Create schemas on test2 database.
hcl := `
schema "public" {
comment = "standard public schema"
}
table "users" {
schema = schema.public
column "id" { type = integer }
}
schema "other" {}
table "posts" {
schema = schema.other
column "id" { type = integer }
}
`
err = os.WriteFile(filepath.Join(dir, "schema.hcl"), []byte(hcl), 0600)
require.NoError(t, err)
out, err := exec.Command(
bin, "schema", "apply",
"-u", fmt.Sprintf("postgres://postgres:pass@localhost:%d/test2?sslmode=disable", t.port),
"-f", filepath.Join(dir, "schema.hcl"),
"--auto-approve",
).CombinedOutput()
require.NoError(t, err, string(out))
// Diff a database with different one.
require.Equal(t, `-- Add new schema named "other"
CREATE SCHEMA "other";
-- Create "users" table
CREATE TABLE "public"."users" ("id" integer NOT NULL);
-- Create "posts" table
CREATE TABLE "other"."posts" ("id" integer NOT NULL);`, diff("test1?sslmode=disable", "test2?sslmode=disable"))
// Diffing schema should both tables and comments (from 'public' to 'other').
require.Equal(t, `-- Create "users" table
CREATE TABLE "users" ("id" integer NOT NULL);
-- Drop "posts" table
DROP TABLE "posts";`, diff("test2?sslmode=disable&search_path=other", "test2?sslmode=disable&search_path=public"))
// diff between schema and database
out, err = exec.Command(
bin, "schema", "diff",
"--from", fmt.Sprintf("postgres://postgres:pass@localhost:%d/test2?sslmode=disable", t.port),
"--to", fmt.Sprintf("postgres://postgres:pass@localhost:%d/test2?sslmode=disable&search_path=public", t.port),
).CombinedOutput()
require.Error(t, err, string(out))
require.Equal(t, "Error: cannot diff a schema \"public\" with a database connection. See: https://atlasgo.io/url\n", string(out))
})
}
func TestPostgres_DefaultsHCL(t *testing.T) {
n := "atlas_defaults"
pgRun(t, func(t *pgTest) {
ddl := `
create table atlas_defaults
(
string varchar(255) default 'hello_world',
quoted varchar(100) default 'never say "never"',
tBit bit(10) default b'10101',
ts timestamp default CURRENT_TIMESTAMP,
tstz timestamp with time zone default CURRENT_TIMESTAMP,
number int default 42
)
`
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
spec, err := postgres.MarshalHCL(realm.Schemas[0])
require.NoError(t, err)
var s schema.Schema
err = postgres.EvalHCLBytes(spec, &s, nil)
require.NoError(t, err)
t.dropTables(n)
t.applyHcl(string(spec))
ensureNoChange(t, realm.Schemas[0].Tables[0])
})
}
func TestPostgres_Sanity(t *testing.T) {
n := "atlas_types_sanity"
ddl := `
DROP TYPE IF EXISTS address;
CREATE TYPE address AS (city VARCHAR(90), street VARCHAR(90));
create table atlas_types_sanity
(
"tBit" bit(10) default b'100' null,
"tBitVar" bit varying(10) default b'100' null,
"tBoolean" boolean default false not null,
"tBool" bool default false not null,
"tBytea" bytea default E'\\001' not null,
"tCharacter" character(10) default 'atlas' null,
"tChar" char(10) default 'atlas' null,
"tCharVar" character varying(10) default 'atlas' null,
"tVarChar" varchar(10) default 'atlas' null,
"tText" text default 'atlas' null,
"tSmallInt" smallint default '10' null,
"tInteger" integer default '10' null,
"tBigInt" bigint default '10' null,
"tInt" int default '10' null,
"tInt2" int2 default '10' null,
"tInt4" int4 default '10' null,
"tInt8" int8 default '10' null,
"tCIDR" cidr default '127.0.0.1' null,
"tInet" inet default '127.0.0.1' null,
"tMACAddr" macaddr default '08:00:2b:01:02:03' null,
"tMACAddr8" macaddr8 default '08:00:2b:01:02:03:04:05' null,
"tCircle" circle default null,
"tLine" line default null,
"tLseg" lseg default null,
"tBox" box default null,
"tPath" path default null,
"tPoint" point default null,
"tDate" date default current_date null,
"tTime" time default current_time null,
"tTimeWTZ" time with time zone default current_time null,
"tTimeWOTZ" time without time zone default current_time null,
"tTimestamp" timestamp default now() null,
"tTimestampTZ" timestamptz default now() null,
"tTimestampWTZ" timestamp with time zone default now() null,
"tTimestampWOTZ" timestamp without time zone default now() null,
"tTimestampPrec" timestamp(4) default now() null,
"tDouble" double precision default 0 null,
"tReal" real default 0 null,
"tFloat8" float8 default 0 null,
"tFloat4" float4 default 0 null,
"tNumeric" numeric default 0 null,
"tDecimal" decimal default 0 null,
"tSmallSerial" smallserial ,
"tSerial" serial ,
"tBigSerial" bigserial ,
"tSerial2" serial2 ,
"tSerial4" serial4 ,
"tSerial8" serial8 ,
"tArray" text[10][10] default '{}' null,
"tXML" xml default 'foo' null,
"tJSON" json default '{"key":"value"}' null,
"tJSONB" jsonb default '{"key":"value"}' null,
"tUUID" uuid default 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11' null,
"tMoney" money default 18 null,
"tInterval" interval default '4 hours' null,
"tUserDefined" address default '("ab","cd")' null
);
`
pgRun(t, func(t *pgTest) {
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
require.Len(t, realm.Schemas, 1)
ts, ok := realm.Schemas[0].Table(n)
require.True(t, ok)
require.Len(t, ts.Attrs, 1)
require.IsType(t, &postgres.OID{}, ts.Attrs[0])
for _, c := range ts.Columns {
c.Attrs = nil // Skip comparing attributes, due to ent/oss differences.
}
expected := schema.Table{
Name: n,
Attrs: ts.Attrs,
Schema: realm.Schemas[0],
Columns: []*schema.Column{
{
Name: "tBit",
Type: &schema.ColumnType{Type: &postgres.BitType{T: "bit", Len: 10}, Raw: "bit", Null: true},
Default: &schema.RawExpr{X: t.valueByVersion(map[string]string{"postgres10": "B'100'::\"bit\""}, "'100'::\"bit\"")},
},
{
Name: "tBitVar",
Type: &schema.ColumnType{Type: &postgres.BitType{T: "bit varying", Len: 10}, Raw: "bit varying", Null: true},
Default: &schema.RawExpr{X: t.valueByVersion(map[string]string{"postgres10": "B'100'::\"bit\""}, "'100'::\"bit\"")},
},
{
Name: "tBoolean",
Type: &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}, Raw: "boolean", Null: false},
Default: &schema.Literal{V: "false"},
},
{
Name: "tBool",
Type: &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}, Raw: "boolean", Null: false},
Default: &schema.Literal{V: "false"},
},
{
Name: "tBytea",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "bytea"}, Raw: "bytea", Null: false},
Default: &schema.Literal{V: "'\\x01'"},
},
{
Name: "tCharacter",
Type: &schema.ColumnType{Type: &schema.StringType{T: "character", Size: 10}, Raw: "character", Null: true},
Default: &schema.Literal{V: "'atlas'"},
},
{
Name: "tChar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "character", Size: 10}, Raw: "character", Null: true},
Default: &schema.Literal{V: "'atlas'"},
},
{
Name: "tCharVar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "character varying", Size: 10}, Raw: "character varying", Null: true},
Default: &schema.Literal{V: "'atlas'"},
},
{
Name: "tVarChar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "character varying", Size: 10}, Raw: "character varying", Null: true},
Default: &schema.Literal{V: "'atlas'"},
},
{
Name: "tText",
Type: &schema.ColumnType{Type: &schema.StringType{T: "text"}, Raw: "text", Null: true},
Default: &schema.Literal{V: "'atlas'"},
},
{
Name: "tSmallInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "smallint"}, Raw: "smallint", Null: true},
Default: &schema.Literal{V: "10"},
},
{
Name: "tInteger",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Raw: "integer", Null: true},
Default: &schema.Literal{V: "10"},
},
{
Name: "tBigInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Raw: "bigint", Null: true},
Default: &schema.Literal{V: "10"},
},
{
Name: "tInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Raw: "integer", Null: true},
Default: &schema.Literal{V: "10"},
},
{
Name: "tInt2",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "smallint"}, Raw: "smallint", Null: true},
Default: &schema.Literal{V: "10"},
},
{
Name: "tInt4",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Raw: "integer", Null: true},
Default: &schema.Literal{V: "10"},
},
{
Name: "tInt8",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Raw: "bigint", Null: true},
Default: &schema.Literal{V: "10"},
},
{
Name: "tCIDR",
Type: &schema.ColumnType{Type: &postgres.NetworkType{T: "cidr"}, Raw: "cidr", Null: true},
Default: &schema.Literal{V: "'127.0.0.1/32'"},
},
{
Name: "tInet",
Type: &schema.ColumnType{Type: &postgres.NetworkType{T: "inet"}, Raw: "inet", Null: true},
Default: &schema.Literal{V: "'127.0.0.1'"},
},
{
Name: "tMACAddr",
Type: &schema.ColumnType{Type: &postgres.NetworkType{T: "macaddr"}, Raw: "macaddr", Null: true},
Default: &schema.Literal{V: "'08:00:2b:01:02:03'"},
},
{
Name: "tMACAddr8",
Type: &schema.ColumnType{Type: &postgres.NetworkType{T: "macaddr8"}, Raw: "macaddr8", Null: true},
Default: &schema.Literal{V: "'08:00:2b:01:02:03:04:05'"},
},
{
Name: "tCircle",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "circle"}, Raw: "circle", Null: true},
},
{
Name: "tLine",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "line"}, Raw: "line", Null: true},
},
{
Name: "tLseg",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "lseg"}, Raw: "lseg", Null: true},
},
{
Name: "tBox",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "box"}, Raw: "box", Null: true},
},
{
Name: "tPath",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "path"}, Raw: "path", Null: true},
},
{
Name: "tPoint",
Type: &schema.ColumnType{Type: &schema.SpatialType{T: "point"}, Raw: "point", Null: true},
},
{
Name: "tDate",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "date"}, Raw: "date", Null: true},
Default: &schema.RawExpr{X: "CURRENT_DATE"},
},
{
Name: "tTime",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "time without time zone", Precision: intp(6)}, Raw: "time without time zone", Null: true},
Default: &schema.RawExpr{X: "CURRENT_TIME"},
},
{
Name: "tTimeWTZ",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "time with time zone", Precision: intp(6)}, Raw: "time with time zone", Null: true},
Default: &schema.RawExpr{X: "CURRENT_TIME"},
},
{
Name: "tTimeWOTZ",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "time without time zone", Precision: intp(6)}, Raw: "time without time zone", Null: true},
Default: &schema.RawExpr{X: "CURRENT_TIME"},
},
{
Name: "tTimestamp",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp without time zone", Precision: intp(6)}, Raw: "timestamp without time zone", Null: true},
Default: &schema.RawExpr{X: "now()"},
},
{
Name: "tTimestampTZ",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp with time zone", Precision: intp(6)}, Raw: "timestamp with time zone", Null: true},
Default: &schema.RawExpr{X: "now()"},
},
{
Name: "tTimestampWTZ",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp with time zone", Precision: intp(6)}, Raw: "timestamp with time zone", Null: true},
Default: &schema.RawExpr{X: "now()"},
},
{
Name: "tTimestampWOTZ",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp without time zone", Precision: intp(6)}, Raw: "timestamp without time zone", Null: true},
Default: &schema.RawExpr{X: "now()"},
},
{
Name: "tTimestampPrec",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp without time zone", Precision: intp(4)}, Raw: "timestamp without time zone", Null: true},
Default: &schema.RawExpr{X: "now()"},
},
{
Name: "tDouble",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "double precision", Precision: 53}, Raw: "double precision", Null: true},
Default: &schema.Literal{V: "0"},
},
{
Name: "tReal",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "real", Precision: 24}, Raw: "real", Null: true},
Default: &schema.Literal{V: "0"},
},
{
Name: "tFloat8",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "double precision", Precision: 53}, Raw: "double precision", Null: true},
Default: &schema.Literal{V: "0"},
},
{
Name: "tFloat4",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "real", Precision: 24}, Raw: "real", Null: true},
Default: &schema.Literal{V: "0"},
},
{
Name: "tNumeric",
Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 0}, Raw: "numeric", Null: true},
Default: &schema.Literal{V: "0"},
},
{
Name: "tDecimal",
Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 0}, Raw: "numeric", Null: true},
Default: &schema.Literal{V: "0"},
},
{
Name: "tSmallSerial",
Type: &schema.ColumnType{Type: &postgres.SerialType{T: "smallserial", SequenceName: "atlas_types_sanity_tSmallSerial_seq"}, Raw: "smallserial", Null: false},
},
{
Name: "tSerial",
Type: &schema.ColumnType{Type: &postgres.SerialType{T: "serial", SequenceName: "atlas_types_sanity_tSerial_seq"}, Raw: "serial", Null: false},
},
{
Name: "tBigSerial",
Type: &schema.ColumnType{Type: &postgres.SerialType{T: "bigserial", SequenceName: "atlas_types_sanity_tBigSerial_seq"}, Raw: "bigserial", Null: false},
},
{
Name: "tSerial2",
Type: &schema.ColumnType{Type: &postgres.SerialType{T: "smallserial", SequenceName: "atlas_types_sanity_tSerial2_seq"}, Raw: "smallserial", Null: false},
},
{
Name: "tSerial4",
Type: &schema.ColumnType{Type: &postgres.SerialType{T: "serial", SequenceName: "atlas_types_sanity_tSerial4_seq"}, Raw: "serial", Null: false},
},
{
Name: "tSerial8",
Type: &schema.ColumnType{Type: &postgres.SerialType{T: "bigserial", SequenceName: "atlas_types_sanity_tSerial8_seq"}, Raw: "bigserial", Null: false},
},
{
Name: "tArray",
Type: &schema.ColumnType{Type: &postgres.ArrayType{Type: &schema.StringType{T: "text"}, T: "text[]"}, Raw: "ARRAY", Null: true},
Default: &schema.Literal{
V: "'{}'",
},
},
{
Name: "tXML",
Type: &schema.ColumnType{Type: &postgres.XMLType{T: "xml"}, Raw: "xml", Null: true},
Default: &schema.Literal{
V: "'foo'",
},
},
{
Name: "tJSON",
Type: &schema.ColumnType{Type: &schema.JSONType{T: "json"}, Raw: "json", Null: true},
Default: &schema.Literal{
V: "'{\"key\":\"value\"}'",
},
},
{
Name: "tJSONB",
Type: &schema.ColumnType{Type: &schema.JSONType{T: "jsonb"}, Raw: "jsonb", Null: true},
Default: &schema.Literal{
V: "'{\"key\": \"value\"}'",
},
},
{
Name: "tUUID",
Type: &schema.ColumnType{Type: &schema.UUIDType{T: "uuid"}, Raw: "uuid", Null: true},
Default: &schema.Literal{
V: "'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'",
},
},
{
Name: "tMoney",
Type: &schema.ColumnType{Type: &postgres.CurrencyType{T: "money"}, Raw: "money", Null: true},
Default: &schema.Literal{
V: "18",
},
},
{
Name: "tInterval",
Type: &schema.ColumnType{Type: &postgres.IntervalType{T: "interval", Precision: intp(6)}, Raw: "interval", Null: true},
Default: &schema.RawExpr{
X: "'04:00:00'::interval",
},
},
{
Name: "tUserDefined",
Type: &schema.ColumnType{Type: &postgres.UserDefinedType{T: "public.address", C: "c"}, Raw: "USER-DEFINED", Null: true},
Default: &schema.RawExpr{
X: "'(ab,cd)'::public.address",
},
},
},
}
require.EqualValues(t, &expected, ts)
})
t.Run("ImplicitIndexes", func(t *testing.T) {
pgRun(t, func(t *pgTest) {
testImplicitIndexes(t, t.db)
})
})
}
func (t *pgTest) url(schema string) string {
return t.dbURL("test", schema)
}
func (t *pgTest) dbURL(db, schema string) string {
var (
format = "postgres://postgres:pass@localhost:%d/%s?sslmode=disable"
args = []any{t.port, db}
)
if schema != "" {
format += "&search_path=%s"
args = append(args, schema)
}
return fmt.Sprintf(format, args...)
}
func (t *pgTest) driver() migrate.Driver {
return t.drv
}
func (t *pgTest) revisionsStorage() migrate.RevisionReadWriter {
return t.rrw
}
func (t *pgTest) applyHcl(spec string) {
realm := t.loadRealm()
var desired schema.Schema
err := postgres.EvalHCLBytes([]byte(spec), &desired, nil)
require.NoError(t, err)
existing := realm.Schemas[0]
diff, err := t.drv.SchemaDiff(existing, &desired)
require.NoError(t, err)
err = t.drv.ApplyChanges(context.Background(), diff)
require.NoError(t, err)
}
func (t *pgTest) valueByVersion(values map[string]string, defaults string) string {
if v, ok := values[t.version]; ok {
return v
}
return defaults
}
func (t *pgTest) loadRealm() *schema.Realm {
r, err := t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{
Schemas: []string{"public"},
Mode: schema.InspectSchemas | schema.InspectTables | schema.InspectTypes,
})
require.NoError(t, err)
return r
}
func (t *pgTest) loadUsers() *schema.Table {
return t.loadTable("users")
}
func (t *pgTest) loadPosts() *schema.Table {
return t.loadTable("posts")
}
func (t *pgTest) loadTable(name string) *schema.Table {
realm := t.loadRealm()
require.Len(t, realm.Schemas, 1)
table, ok := realm.Schemas[0].Table(name)
require.True(t, ok)
return table
}
func (t *pgTest) users() *schema.Table {
usersT := &schema.Table{
Name: "users",
Schema: t.realm().Schemas[0],
Columns: []*schema.Column{
{
Name: "id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}},
Attrs: []schema.Attr{&postgres.Identity{}},
},
{
Name: "x",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}},
},
},
}
usersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}
return usersT
}
func (t *pgTest) posts() *schema.Table {
usersT := t.users()
postsT := &schema.Table{
Name: "posts",
Schema: t.realm().Schemas[0],
Columns: []*schema.Column{
{
Name: "id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}},
Attrs: []schema.Attr{&postgres.Identity{}},
},
{
Name: "author_id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.Literal{V: "10"},
},
{
Name: "ctime",
Type: &schema.ColumnType{Raw: "timestamp", Type: &schema.TimeType{T: "timestamp"}},
Default: &schema.RawExpr{
X: "CURRENT_TIMESTAMP",
},
},
},
Attrs: []schema.Attr{
&schema.Comment{Text: "posts comment"},
},
}
postsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}
postsT.Indexes = []*schema.Index{
{Name: "author_id", Parts: []*schema.IndexPart{{C: postsT.Columns[1]}}},
{Name: "id_author_id_unique", Unique: true, Parts: []*schema.IndexPart{{C: postsT.Columns[1]}, {C: postsT.Columns[0]}}},
}
postsT.ForeignKeys = []*schema.ForeignKey{
{Symbol: "author_id", Table: postsT, Columns: postsT.Columns[1:2], RefTable: usersT, RefColumns: usersT.Columns[:1], OnDelete: schema.NoAction},
}
return postsT
}
func (t *pgTest) realm() *schema.Realm {
r := &schema.Realm{
Schemas: []*schema.Schema{
{
Name: "public",
Attrs: []schema.Attr{
&schema.Comment{Text: "standard public schema"},
},
},
},
}
r.Schemas[0].Realm = r
return r
}
func (t *pgTest) diff(t1, t2 *schema.Table) []schema.Change {
changes, err := t.drv.TableDiff(t1, t2)
require.NoError(t, err)
return changes
}
func (t *pgTest) migrate(changes ...schema.Change) {
err := t.drv.ApplyChanges(context.Background(), changes)
require.NoError(t, err)
}
func (t *pgTest) dropTables(names ...string) {
t.Cleanup(func() {
_, err := t.db.Exec("DROP TABLE IF EXISTS " + strings.Join(names, ", "))
require.NoError(t.T, err, "drop tables %q", names)
})
}
func (t *pgTest) dropSchemas(names ...string) {
t.Cleanup(func() {
_, err := t.db.Exec("DROP SCHEMA IF EXISTS " + strings.Join(names, ", ") + " CASCADE")
require.NoError(t.T, err, "drop schema %q", names)
})
}
================================================
FILE: internal/integration/script_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package integration
import (
"bytes"
"context"
"database/sql"
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"slices"
"strconv"
"strings"
"testing"
"unicode"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/mysql"
"ariga.io/atlas/sql/postgres"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
"ariga.io/atlas/sql/sqlite"
"github.com/pkg/diff"
"github.com/rogpeppe/go-internal/testscript"
"github.com/stretchr/testify/require"
)
func TestMySQL_Script(t *testing.T) {
myRun(t, func(t *myTest) {
testscript.Run(t.T, testscript.Params{
Dir: "testdata/mysql",
Setup: t.setupScript,
Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){
"only": cmdOnly,
"apply": t.cmdApply,
"exist": t.cmdExist,
"synced": t.cmdSynced,
"cmphcl": t.cmdCmpHCL,
"cmpshow": t.cmdCmpShow,
"cmpmig": t.cmdCmpMig,
"execsql": t.cmdExec,
"atlas": t.cmdCLI,
"clearSchema": t.clearSchema,
"validJSON": validJSON,
},
})
})
}
func TestPostgres_Script(t *testing.T) {
pgRun(t, func(t *pgTest) {
testscript.Run(t.T, testscript.Params{
Dir: "testdata/postgres",
Setup: t.setupScript,
Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){
"only": cmdOnly,
"apply": t.cmdApply,
"exist": t.cmdExist,
"synced": t.cmdSynced,
"cmphcl": t.cmdCmpHCL,
"cmpshow": t.cmdCmpShow,
"cmpmig": t.cmdCmpMig,
"execsql": t.cmdExec,
"atlas": t.cmdCLI,
"clearSchema": t.clearSchema,
},
})
})
}
func TestSQLite_Script(t *testing.T) {
tt := &liteTest{T: t}
testscript.Run(t, testscript.Params{
Dir: "testdata/sqlite",
Setup: tt.setupScript,
Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){
"apply": tt.cmdApply,
"exist": tt.cmdExist,
"synced": tt.cmdSynced,
"cmphcl": tt.cmdCmpHCL,
"cmpshow": tt.cmdCmpShow,
"cmpmig": tt.cmdCmpMig,
"execsql": tt.cmdExec,
"atlas": tt.cmdCLI,
"clearSchema": tt.clearSchema,
},
})
}
var keyT struct{}
func (t *myTest) setupScript(env *testscript.Env) error {
attrs := t.defaultAttrs()
env.Setenv("version", t.version)
env.Setenv("charset", attrs[0].(*schema.Charset).V)
env.Setenv("collate", attrs[1].(*schema.Collation).V)
if err := replaceDBURL(env, t.url("")); err != nil {
return err
}
return setupScript(env, t.db,
"CREATE SCHEMA IF NOT EXISTS %s",
"DROP SCHEMA IF EXISTS %s",
func(tt testing.TB, schema string) migrate.Driver {
dev, err := sqlclient.Open(context.Background(), fmt.Sprintf("mysql://root:pass@localhost:%d/%s", t.port, schema))
require.NoError(tt, err)
tt.Cleanup(func() { require.NoError(tt, dev.Close()) })
return dev.Driver
})
}
func replaceDBURL(env *testscript.Env, url string) error {
// Set the workdir in the test atlas.hcl file.
projectFile := filepath.Join(env.WorkDir, "atlas.hcl")
if b, err := os.ReadFile(projectFile); err == nil {
rep := strings.ReplaceAll(string(b), "URL", url)
return os.WriteFile(projectFile, []byte(rep), 0600)
}
return nil
}
func (t *pgTest) setupScript(env *testscript.Env) error {
env.Setenv("version", t.version)
u := strings.ReplaceAll(t.url(""), "/test", "/")
if err := replaceDBURL(env, u); err != nil {
return err
}
return setupScript(env, t.db,
"CREATE SCHEMA IF NOT EXISTS %s",
"DROP SCHEMA IF EXISTS %s CASCADE",
func(tt testing.TB, schema string) migrate.Driver {
dev, err := sqlclient.Open(context.Background(), fmt.Sprintf("postgres://postgres:pass@localhost:%d/test?search_path=%s&sslmode=disable", t.port, schema))
require.NoError(tt, err)
tt.Cleanup(func() { require.NoError(tt, dev.Close()) })
return dev.Driver
})
}
func setupScript(env *testscript.Env, db *sql.DB, createCmd, dropCmd string, open func(testing.TB, string) migrate.Driver) error {
ctx := context.Background()
conn, err := db.Conn(ctx)
if err != nil {
return err
}
name := strings.ReplaceAll(filepath.Base(env.WorkDir), "-", "_")
devname := fmt.Sprintf("%s_dev", name)
env.Setenv("db", name)
env.Setenv("dev", devname)
if _, err := conn.ExecContext(ctx, fmt.Sprintf(createCmd, name)); err != nil {
return err
}
if _, err := conn.ExecContext(ctx, fmt.Sprintf(createCmd, devname)); err != nil {
return err
}
// Env has a T() method that returns the *testing.T.
// We need to cast it to the testing.TB interface
// to be able to use the Cleanup method.
tt := env.T().(testing.TB)
tt.Cleanup(func() {
if _, err := conn.ExecContext(ctx, fmt.Sprintf(dropCmd, name)); err != nil {
tt.Fatal(err)
}
if _, err := conn.ExecContext(ctx, fmt.Sprintf(dropCmd, devname)); err != nil {
tt.Fatal(err)
}
if err := conn.Close(); err != nil {
tt.Fatal(err)
}
})
// Dev-driver per testscript schema to allow concurrent tests.
env.Values["drv"] = open(tt, name)
env.Values["dev"] = open(tt, devname)
// Store the testscript.T for later use.
// See "only" function below.
env.Values[keyT] = env.T()
env.Setenv(atlasPathKey, cliPath(tt))
return nil
}
var (
keyDB *sql.DB
keyDrv *sqlite.Driver
)
const atlasPathKey = "cli.atlas"
func (t *liteTest) setupScript(env *testscript.Env) error {
db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared&_fk=1",
filepath.Join(env.WorkDir, "atlas.sqlite")))
require.NoError(t, err)
env.Defer(func() {
require.NoError(t, db.Close())
})
drv, err := sqlite.Open(db)
require.NoError(t, err)
env.Setenv("db", "main")
// Attach connection and driver to the
// environment as tests run in parallel.
env.Values[keyDB] = db
env.Values[keyDrv] = drv
env.Setenv(atlasPathKey, cliPath(t.T))
// Set the workdir in the test atlas.hcl file.
projectFile := filepath.Join(env.WorkDir, "atlas.hcl")
if b, err := os.ReadFile(projectFile); err == nil {
rep := strings.ReplaceAll(string(b), "URL",
fmt.Sprintf("sqlite://file:%s/atlas.sqlite?cache=shared&_fk=1", env.WorkDir))
return os.WriteFile(projectFile, []byte(rep), 0600)
}
return nil
}
// cmdOnly executes only tests that their driver version matches the given pattern.
// For example, "only 8" or "only 8 maria*"
func cmdOnly(ts *testscript.TestScript, neg bool, args []string) {
ver := ts.Getenv("version")
for i := range args {
re, rerr := regexp.Compile(`(?mi)` + args[i])
ts.Check(rerr)
if !neg == re.MatchString(ver) {
return
}
}
// This is not an elegant way to get the created testing.T for the script,
// but we need some workaround to get it in order to skip specific tests.
ts.Value(keyT).(testscript.T).Skip("skip version", ver)
}
func (t *myTest) cmdCmpShow(ts *testscript.TestScript, _ bool, args []string) {
cmdCmpShow(ts, args, func(schema, name string) (string, error) {
var create string
if err := t.db.QueryRow(fmt.Sprintf("SHOW CREATE TABLE `%s`.`%s`", schema, name)).Scan(&name, &create); err != nil {
return "", err
}
i := strings.LastIndexByte(create, ')')
create, opts := create[:i+1], strings.Fields(create[i+1:])
for _, opt := range opts {
switch strings.Split(opt, "=")[0] {
// Keep only options that are relevant for the tests.
case "AUTO_INCREMENT", "COMMENT":
create += " " + opt
}
}
return create, nil
})
}
func (t *pgTest) cmdCmpShow(ts *testscript.TestScript, _ bool, args []string) {
cmdCmpShow(ts, args, func(schema, name string) (string, error) {
buf, err := exec.Command("docker", "ps", "-qa", "-f", fmt.Sprintf("publish=%d", t.port)).CombinedOutput()
if err != nil {
return "", fmt.Errorf("get container id %q: %v", buf, err)
}
buf = bytes.TrimSpace(buf)
if len(bytes.Split(buf, []byte("\n"))) > 1 {
return "", fmt.Errorf("multiple container ids found: %q", buf)
}
cmd := exec.Command("docker", "exec", string(buf), "psql", "-U", "postgres", "-d", "test", "-c", fmt.Sprintf(`\d %s.%s`, schema, name))
// Use "cmd.String" to debug command.
buf, err = cmd.CombinedOutput()
if err != nil {
return "", err
}
lines := strings.Split(string(buf), "\n")
for i := range lines {
lines[i] = strings.TrimRightFunc(lines[i], unicode.IsSpace)
}
return strings.Join(lines, "\n"), err
})
}
func (t *liteTest) cmdCmpShow(ts *testscript.TestScript, _ bool, args []string) {
cmdCmpShow(ts, args, func(_, name string) (string, error) {
var (
stmts []string
db = ts.Value(keyDB).(*sql.DB)
)
rows, err := db.Query("SELECT sql FROM sqlite_schema where tbl_name = ?", name)
if err != nil {
return "", fmt.Errorf("querying schema")
}
defer rows.Close()
for rows.Next() {
var s string
if err := rows.Scan(&s); err != nil {
return "", err
}
stmts = append(stmts, s)
}
return strings.Join(stmts, "\n"), nil
})
}
func cmdCmpShow(ts *testscript.TestScript, args []string, show func(schema, name string) (string, error)) {
if len(args) < 2 {
ts.Fatalf("invalid number of args to 'cmpshow': %d", len(args))
}
var (
ver = ts.Getenv("version")
fname = args[len(args)-1]
stmts = make([]string, 0, len(args)-1)
)
for _, name := range args[:len(args)-1] {
create, err := show(ts.Getenv("db"), name)
if err != nil {
ts.Fatalf("show table %q: %v", name, err)
}
stmts = append(stmts, create)
}
// Check if there is a file prefixed by database version (1.sql and /1.sql).
if _, err := os.Stat(ts.MkAbs(filepath.Join(ver, fname))); err == nil {
fname = filepath.Join(ver, fname)
}
t1, t2 := strings.Join(stmts, "\n"), ts.ReadFile(fname)
if strings.TrimSpace(t1) == strings.TrimSpace(t2) {
return
}
var sb strings.Builder
ts.Check(diff.Text("show", fname, t1, t2, &sb))
ts.Fatalf("\n%s", sb.String())
}
func (t *myTest) cmdCmpHCL(ts *testscript.TestScript, _ bool, args []string) {
r := strings.NewReplacer("$charset", ts.Getenv("charset"), "$collate", ts.Getenv("collate"), "$db", ts.Getenv("db"))
cmdCmpHCL(ts, args, func(name string) (string, error) {
s, err := ts.Value("drv").(migrate.Driver).InspectSchema(context.Background(), name, nil)
ts.Check(err)
buf, err := mysql.MarshalHCL(s)
require.NoError(t, err)
return string(buf), nil
}, func(s string) string {
return r.Replace(ts.ReadFile(s))
})
}
func (t *pgTest) cmdCmpHCL(ts *testscript.TestScript, _ bool, args []string) {
cmdCmpHCL(ts, args, func(name string) (string, error) {
s, err := ts.Value("drv").(migrate.Driver).InspectSchema(context.Background(), name, nil)
ts.Check(err)
buf, err := postgres.MarshalHCL(s)
require.NoError(t, err)
return string(buf), nil
}, func(s string) string {
return strings.ReplaceAll(ts.ReadFile(s), "$db", ts.Getenv("db"))
})
}
func (t *liteTest) cmdCmpHCL(ts *testscript.TestScript, _ bool, args []string) {
cmdCmpHCL(ts, args, func(name string) (string, error) {
s, err := ts.Value(keyDrv).(migrate.Driver).InspectSchema(context.Background(), "main", nil)
ts.Check(err)
buf, err := sqlite.MarshalHCL(s)
require.NoError(t, err)
return string(buf), nil
}, func(s string) string {
return strings.ReplaceAll(ts.ReadFile(s), "$db", ts.Getenv("db"))
})
}
func cmdCmpHCL(ts *testscript.TestScript, args []string, inspect func(schema string) (string, error), read ...func(string) string) {
if len(args) != 1 {
ts.Fatalf("invalid number of args to 'cmpinspect': %d", len(args))
}
if len(read) == 0 {
read = append(read, ts.ReadFile)
}
var (
fname = args[0]
ver = ts.Getenv("version")
)
f1, err := inspect(ts.Getenv("db"))
if err != nil {
ts.Fatalf("inspect schema %q: %v", ts.Getenv("db"), err)
}
// Check if there is a file prefixed by database version (1.sql and /1.sql).
if _, err := os.Stat(ts.MkAbs(filepath.Join(ver, fname))); err == nil {
fname = filepath.Join(ver, fname)
}
f2 := read[0](fname)
if strings.TrimSpace(f1) == strings.TrimSpace(f2) {
return
}
var sb strings.Builder
ts.Check(diff.Text("inspect", fname, f1, f2, &sb))
ts.Fatalf("\n%s", sb.String())
}
func (t *myTest) cmdExec(ts *testscript.TestScript, _ bool, args []string) {
cmdExec(ts, args, t.db)
}
func (t *pgTest) cmdExec(ts *testscript.TestScript, _ bool, args []string) {
cmdExec(ts, args, t.db)
}
func (t *liteTest) cmdExec(ts *testscript.TestScript, _ bool, args []string) {
cmdExec(ts, args, ts.Value(keyDB).(*sql.DB))
}
func (t *myTest) cmdCLI(ts *testscript.TestScript, neg bool, args []string) {
cmdCLI(ts, neg, args, t.url(ts.Getenv("db")), t.url(ts.Getenv("dev")), ts.Getenv(atlasPathKey))
}
func (t *pgTest) cmdCLI(ts *testscript.TestScript, neg bool, args []string) {
cmdCLI(ts, neg, args, t.url(ts.Getenv("db")), t.url(ts.Getenv("dev")), ts.Getenv(atlasPathKey))
}
func (t *liteTest) cmdCLI(ts *testscript.TestScript, neg bool, args []string) {
dbURL := fmt.Sprintf("sqlite://file:%s/atlas.sqlite?cache=shared&_fk=1", ts.Getenv("WORK"))
cmdCLI(ts, neg, args, dbURL, "sqlite://dev?mode=memory", ts.Getenv(atlasPathKey))
}
func cmdCLI(ts *testscript.TestScript, neg bool, args []string, dbURL, devURL, cliPath string, envs ...string) {
var (
workDir = ts.Getenv("WORK")
r = strings.NewReplacer("URL", dbURL, "DEV_URL", devURL, "$db", ts.Getenv("db"))
)
for i, arg := range args {
args[i] = r.Replace(arg)
}
// Whenever a migrate diff/apply command is executed, increase the default lock
// timeout to 30s, as the default (10s) for synchronizing all our tests.
if len(args) > 1 && args[0] == "migrate" && (args[1] == "diff" || args[1] == "apply") && !slices.Contains(args, "--lock-timeout") {
args = append(args, "--lock-timeout", "30s")
}
switch l := len(args); {
// If command was run with a unix redirect-like suffix.
case l > 1 && args[l-2] == ">":
outPath := filepath.Join(workDir, args[l-1])
f, err := os.Create(outPath)
ts.Check(err)
defer f.Close()
cmd := exec.Command(cliPath, args[0:l-2]...)
cmd.Stdout = f
stderr := &bytes.Buffer{}
cmd.Stderr = stderr
cmd.Dir = workDir
cmd.Env = append(cmd.Env,
"HOME="+ts.Getenv("HOME"),
"PATH="+ts.Getenv("PATH"),
"DOCKER_HOST="+ts.Getenv("DOCKER_HOST"),
)
for _, env := range envs {
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", env, ts.Getenv(env)))
}
if err := cmd.Run(); err != nil && !neg {
ts.Fatalf("\n[stderr]\n%s", stderr)
}
default:
err := ts.Exec(cliPath, args...)
if !neg {
ts.Check(err)
}
if neg && err == nil {
ts.Fatalf("expected fail")
}
}
}
func (t *myTest) cmdCmpMig(ts *testscript.TestScript, neg bool, args []string) {
cmdCmpMig(ts, neg, args)
}
func (t *pgTest) cmdCmpMig(ts *testscript.TestScript, neg bool, args []string) {
cmdCmpMig(ts, neg, args)
}
func (t *liteTest) cmdCmpMig(ts *testscript.TestScript, neg bool, args []string) {
cmdCmpMig(ts, neg, args)
}
var reLiquibaseChangeset = regexp.MustCompile("--changeset atlas:[0-9]+-[0-9]+")
// cmdCmpMig compares a migration file under migrations with a provided file.
// If the first argument is a filename that does exist, that file is used for comparison.
// If there is no file with that name, the argument is parsed to an integer n and the
// nth sql file is used for comparison. Lexicographic order of
// the files in the directory is used to access the file of interest.
func cmdCmpMig(ts *testscript.TestScript, _ bool, args []string) {
if len(args) < 2 {
ts.Fatalf("invalid number of args to 'cmpmig': %d", len(args))
}
// Check if there is a file prefixed by database version (1.sql and /1.sql).
var (
ver = ts.Getenv("version")
fname = args[1]
)
if _, err := os.Stat(ts.MkAbs(filepath.Join(ver, fname))); err == nil {
fname = filepath.Join(ver, fname)
}
expected := strings.TrimSpace(ts.ReadFile(fname))
dir, err := os.ReadDir(ts.MkAbs("migrations"))
ts.Check(err)
idx, err := strconv.Atoi(args[0])
ts.Check(err)
current := 0
for _, f := range dir {
if f.IsDir() || !strings.HasSuffix(f.Name(), ".sql") {
continue
}
if current == idx {
actual := strings.TrimSpace(ts.ReadFile(filepath.Join("migrations", f.Name())))
exLines, acLines := strings.Split(actual, "\n"), strings.Split(expected, "\n")
if len(exLines) != len(acLines) {
var sb strings.Builder
ts.Check(diff.Text(f.Name(), args[1], actual, expected, &sb))
ts.Fatalf("\n%s", sb.String())
}
for i := range exLines {
// Skip liquibase changeset comments since they contain a timestamp.
if reLiquibaseChangeset.MatchString(acLines[i]) {
continue
}
if exLines[i] != acLines[i] {
var sb strings.Builder
ts.Check(diff.Text(f.Name(), args[1], actual, expected, &sb))
ts.Fatalf("\n%s", sb.String())
}
}
return
}
current++
}
ts.Fatalf("could not find the #%d migration", idx)
}
func cmdExec(ts *testscript.TestScript, args []string, db *sql.DB) {
if len(args) == 0 {
ts.Fatalf("missing statements for 'execsql'")
}
for i := range args {
s := strings.ReplaceAll(args[i], "$db", ts.Getenv("db"))
_, err := db.Exec(s)
ts.Check(err)
}
}
func (t *myTest) cmdExist(ts *testscript.TestScript, neg bool, args []string) {
cmdExist(ts, neg, args, func(schema, name string) (bool, error) {
var b bool
if err := t.db.QueryRow("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?", schema, name).Scan(&b); err != nil {
return false, err
}
return b, nil
})
}
func (t *pgTest) cmdExist(ts *testscript.TestScript, neg bool, args []string) {
cmdExist(ts, neg, args, func(schema, name string) (bool, error) {
var b bool
if err := t.db.QueryRow("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = $1 AND TABLE_NAME = $2", schema, name).Scan(&b); err != nil {
return false, err
}
return b, nil
})
}
func (t *liteTest) cmdExist(ts *testscript.TestScript, neg bool, args []string) {
cmdExist(ts, neg, args, func(_, name string) (bool, error) {
var (
b bool
db = ts.Value(keyDB).(*sql.DB)
)
if err := db.QueryRow("SELECT COUNT(*) FROM sqlite_master WHERE `type`='table' AND `name` = ?", name).Scan(&b); err != nil {
return false, err
}
return b, nil
})
}
func cmdExist(ts *testscript.TestScript, neg bool, args []string, exists func(schema, name string) (bool, error)) {
for _, name := range args {
b, err := exists(ts.Getenv("db"), name)
if err != nil {
ts.Fatalf("failed query table existence %q: %v", name, err)
}
if !b != neg {
ts.Fatalf("table %q existence failed", name)
}
}
}
func (t *myTest) cmdSynced(ts *testscript.TestScript, neg bool, args []string) {
cmdSynced(ts, neg, args, t.hclDiff)
}
func (t *myTest) cmdApply(ts *testscript.TestScript, neg bool, args []string) {
cmdApply(ts, neg, args, ts.Value("drv").(migrate.Driver).ApplyChanges, t.hclDiff)
}
func (t *myTest) hclDiff(ts *testscript.TestScript, name string) ([]schema.Change, error) {
var (
desired = &schema.Schema{}
f = ts.ReadFile(name)
ctx = context.Background()
drv = ts.Value("drv").(migrate.Driver)
r = strings.NewReplacer("$charset", ts.Getenv("charset"), "$collate", ts.Getenv("collate"), "$db", ts.Getenv("db"))
)
ts.Check(mysql.EvalHCLBytes([]byte(r.Replace(f)), desired, nil))
current, err := drv.InspectSchema(ctx, desired.Name, nil)
ts.Check(err)
desired, err = ts.Value("dev").(schema.Normalizer).NormalizeSchema(ctx, desired)
// Normalization and diffing errors should
// be returned to the caller.
if err != nil {
return nil, err
}
changes, err := drv.SchemaDiff(current, desired)
if err != nil {
return nil, err
}
return changes, nil
}
func (t *pgTest) cmdSynced(ts *testscript.TestScript, neg bool, args []string) {
cmdSynced(ts, neg, args, t.hclDiff)
}
func (t *pgTest) cmdApply(ts *testscript.TestScript, neg bool, args []string) {
cmdApply(ts, neg, args, ts.Value("drv").(migrate.Driver).ApplyChanges, t.hclDiff)
}
func (t *pgTest) hclDiff(ts *testscript.TestScript, name string) ([]schema.Change, error) {
var (
desired = &schema.Schema{}
ctx = context.Background()
drv = ts.Value("drv").(migrate.Driver)
f = strings.ReplaceAll(ts.ReadFile(name), "$db", ts.Getenv("db"))
)
ts.Check(postgres.EvalHCLBytes([]byte(f), desired, nil))
current, err := drv.InspectSchema(ctx, desired.Name, nil)
ts.Check(err)
desired, err = ts.Value("dev").(schema.Normalizer).NormalizeSchema(ctx, desired)
// Normalization and diffing errors should
// be returned to the caller.
if err != nil {
return nil, err
}
changes, err := drv.SchemaDiff(current, desired)
if err != nil {
return nil, err
}
return changes, nil
}
func (t *liteTest) cmdSynced(ts *testscript.TestScript, neg bool, args []string) {
cmdSynced(ts, neg, args, t.hclDiff)
}
func (t *liteTest) cmdApply(ts *testscript.TestScript, neg bool, args []string) {
cmdApply(ts, neg, args, ts.Value(keyDrv).(*sqlite.Driver).ApplyChanges, t.hclDiff)
}
func (t *liteTest) hclDiff(ts *testscript.TestScript, name string) ([]schema.Change, error) {
var (
desired = &schema.Schema{}
f = ts.ReadFile(name)
drv = ts.Value(keyDrv).(*sqlite.Driver)
)
ts.Check(sqlite.EvalHCLBytes([]byte(f), desired, nil))
current, err := drv.InspectSchema(context.Background(), desired.Name, nil)
ts.Check(err)
changes, err := drv.SchemaDiff(current, desired)
// Diff errors should return to the caller.
if err != nil {
return nil, err
}
return changes, nil
}
func (t *myTest) clearSchema(ts *testscript.TestScript, _ bool, args []string) {
if len(args) == 0 {
args = append(args, ts.Getenv("db"))
}
_, err := t.db.Exec("DROP DATABASE IF EXISTS " + args[0])
ts.Check(err)
_, err = t.db.Exec("CREATE DATABASE IF NOT EXISTS " + args[0])
ts.Check(err)
}
func (t *pgTest) clearSchema(ts *testscript.TestScript, _ bool, args []string) {
if len(args) == 0 {
args = append(args, ts.Getenv("db"))
}
_, err := t.db.Exec(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", args[0]))
ts.Check(err)
_, err = t.db.Exec("CREATE SCHEMA IF NOT EXISTS " + args[0])
ts.Check(err)
}
func (t *liteTest) clearSchema(ts *testscript.TestScript, _ bool, _ []string) {
for _, stmt := range []string{
"PRAGMA writable_schema = 1;",
"DELETE FROM sqlite_master WHERE type IN ('table', 'index', 'trigger');",
"PRAGMA writable_schema = 0;",
"VACUUM;",
} {
_, err := ts.Value(keyDB).(*sql.DB).Exec(stmt)
ts.Check(err)
}
}
func cmdSynced(ts *testscript.TestScript, neg bool, args []string, diff func(*testscript.TestScript, string) ([]schema.Change, error)) {
if len(args) != 1 {
ts.Fatalf("unexpected number of args to synced command: %d", len(args))
}
switch changes, err := diff(ts, args[0]); {
case err != nil:
ts.Fatalf("unexpected diff failure on synced: %v", err)
case len(changes) > 0 && !neg:
ts.Fatalf("expect no schema changes, but got: %d", len(changes))
case len(changes) == 0 && neg:
ts.Fatalf("expect schema changes, but there are none")
}
}
func cmdApply(ts *testscript.TestScript, neg bool, args []string, apply func(context.Context, []schema.Change, ...migrate.PlanOption) error, diff func(*testscript.TestScript, string) ([]schema.Change, error)) {
changes, err := diff(ts, args[0])
switch {
case err != nil && !neg:
ts.Fatalf("diff states: %v", err)
// If we expect to fail, and there's a specific error to compare.
case err != nil && len(args) == 2:
matchErr(ts, err, args[1])
return
}
switch err := apply(context.Background(), changes); {
case err != nil && !neg:
ts.Fatalf("apply changes: %v", err)
case err == nil && neg:
ts.Fatalf("unexpected apply success")
// If we expect to fail, and there's a specific error to compare.
case err != nil && len(args) == 2:
matchErr(ts, err, args[1])
// Apply passed. Make sure there is no drift.
case !neg:
changes, err := diff(ts, args[0])
ts.Check(err)
if len(changes) > 0 {
ts.Fatalf("unexpected schema changes: %d", len(changes))
}
}
}
func matchErr(ts *testscript.TestScript, err error, p string) {
re, rerr := regexp.Compile(`(?m)` + regexp.QuoteMeta(p))
ts.Check(rerr)
if !re.MatchString(err.Error()) {
ts.Fatalf("mismatched errors: %v != %s", err, p)
}
}
func validJSON(ts *testscript.TestScript, _ bool, args []string) {
ts.Check(json.Unmarshal([]byte(ts.ReadFile(args[0])), new(map[string]any)))
}
================================================
FILE: internal/integration/sqlite_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package integration
import (
"context"
"database/sql"
"database/sql/driver"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"testing"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/postgres"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlite"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
)
type liteTest struct {
*testing.T
db *sql.DB
drv migrate.Driver
rrw migrate.RevisionReadWriter
file string
}
func liteRun(t *testing.T, fn func(test *liteTest)) {
t.Parallel()
f := path.Join(t.TempDir(), strings.ReplaceAll(t.Name(), "/", "_"))
db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared&_fk=1", f))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, db.Close())
})
drv, err := sqlite.Open(db)
require.NoError(t, err)
tt := &liteTest{T: t, db: db, drv: drv, file: f, rrw: &rrw{}}
fn(tt)
}
func TestSQLite_Executor(t *testing.T) {
liteRun(t, func(t *liteTest) {
testExecutor(t)
})
}
func TestSQLite_AddDropTable(t *testing.T) {
liteRun(t, func(t *liteTest) {
testAddDrop(t)
})
}
func TestSQLite_Relation(t *testing.T) {
liteRun(t, func(t *liteTest) {
testRelation(t)
})
}
func TestSQLite_ColumnCheck(t *testing.T) {
liteRun(t, func(t *liteTest) {
usersT := &schema.Table{
Name: "users",
Attrs: []schema.Attr{schema.NewCheck().SetName("users_c_check").SetExpr("c > 5")},
Columns: []*schema.Column{
{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}},
{Name: "c", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}},
},
}
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
ensureNoChange(t, usersT)
})
}
func TestSQLite_AddIndexedColumns(t *testing.T) {
liteRun(t, func(t *liteTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
// Insert 2 records to the users table, and make sure they are there
// after executing migration.
_, err := t.db.Exec("INSERT INTO users (id) VALUES (1), (2)")
require.NoError(t, err)
usersT.Columns = append(usersT.Columns, &schema.Column{
Name: "a",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Null: true},
Default: &schema.Literal{V: "10"},
}, &schema.Column{
Name: "b",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Null: true},
Default: &schema.Literal{V: "20"},
}, &schema.Column{
Name: "c",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Null: true},
Default: &schema.Literal{V: "30"},
})
usersT.Indexes = append(usersT.Indexes, &schema.Index{
Unique: true,
Name: "id_a_b_c_unique",
Parts: []*schema.IndexPart{{C: usersT.Columns[0]}, {C: usersT.Columns[1]}, {C: usersT.Columns[2]}, {C: usersT.Columns[3]}},
})
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 4, "usersT contains 3 new columns and 1 new index")
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// Scan records from the table to ensure correctness of
// the rows transferring.
rows, err := t.db.Query("SELECT * FROM users")
require.NoError(t, err)
require.True(t, rows.Next())
var v [4]int
require.NoError(t, rows.Scan(&v[0], &v[1], &v[2], &v[3]))
require.Equal(t, [4]int{1, 10, 20, 30}, v)
require.True(t, rows.Next())
require.NoError(t, rows.Scan(&v[0], &v[1], &v[2], &v[3]))
require.Equal(t, [4]int{2, 10, 20, 30}, v)
require.False(t, rows.Next())
require.NoError(t, rows.Close())
// Dropping a column from both table and index.
usersT = t.loadUsers()
idx, ok := usersT.Index("id_a_b_c_unique")
require.True(t, ok)
require.Len(t, idx.Parts, 4)
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
idx.Parts = idx.Parts[:len(idx.Parts)-1]
changes = t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, t.loadUsers())
// Scan records from the table to ensure correctness of
// the rows transferring.
rows, err = t.db.Query("SELECT * FROM users")
require.NoError(t, err)
require.True(t, rows.Next())
var u [3]int
require.NoError(t, rows.Scan(&u[0], &u[1], &u[2]))
require.Equal(t, [3]int{1, 10, 20}, u)
require.True(t, rows.Next())
require.NoError(t, rows.Scan(&u[0], &u[1], &u[2]))
require.Equal(t, [3]int{2, 10, 20}, u)
require.False(t, rows.Next())
require.NoError(t, rows.Close())
})
}
func TestSQLite_AutoIncrement(t *testing.T) {
liteRun(t, func(t *liteTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}}, Attrs: []schema.Attr{sqlite.AutoIncrement{}}},
},
}
usersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
_, err := t.db.Exec("INSERT INTO users DEFAULT VALUES")
require.NoError(t, err)
var id int
err = t.db.QueryRow("SELECT id FROM users").Scan(&id)
require.NoError(t, err)
require.Equal(t, 1, id)
})
}
func TestSQLite_AutoIncrementSequence(t *testing.T) {
// This test shows a bug detected in Ent when working with pre-defined auto-increment start values.
// If there is a change somewhere to create an auto-increment with a start value, Atlas must make sure to create
// an entry in the 'sqlite_sequence' table (and also ensure the table exists before attempting to create the entry).
liteRun(t, func(t *liteTest) {
t1 := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{
Name: "id",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}},
Attrs: []schema.Attr{&sqlite.AutoIncrement{Seq: 10}},
},
},
Attrs: []schema.Attr{&sqlite.AutoIncrement{}},
}
t1.PrimaryKey = &schema.Index{Table: t1, Parts: []*schema.IndexPart{{C: t1.Columns[0]}}}
t1.Columns[0].Indexes = append(t1.Columns[0].Indexes, t1.PrimaryKey)
// Planning the changes should not result in an error.
_ = plan(t, "col_seq", &schema.AddTable{T: t1})
})
}
func TestSQLite_AddColumns(t *testing.T) {
liteRun(t, func(t *liteTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}}, Attrs: []schema.Attr{sqlite.AutoIncrement{}}},
},
}
usersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
_, err := t.db.Exec("INSERT INTO users (id) VALUES (1), (2)")
require.NoError(t, err)
usersT.Columns = append(
usersT.Columns,
&schema.Column{Name: "null_int", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Null: true}},
&schema.Column{Name: "notnull_int", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}}, Default: &schema.Literal{V: "1"}},
&schema.Column{Name: "null_real", Type: &schema.ColumnType{Type: &schema.FloatType{T: "real"}, Null: true}},
&schema.Column{Name: "notnull_real", Type: &schema.ColumnType{Type: &schema.FloatType{T: "real"}}, Default: &schema.Literal{V: "1.0"}},
&schema.Column{Name: "null_text", Type: &schema.ColumnType{Type: &schema.StringType{T: "text"}, Null: true}},
&schema.Column{Name: "notnull_text1", Type: &schema.ColumnType{Type: &schema.StringType{T: "text"}}, Default: &schema.Literal{V: "hello"}},
&schema.Column{Name: "notnull_text2", Type: &schema.ColumnType{Type: &schema.StringType{T: "text"}}, Default: &schema.Literal{V: "'hello'"}},
&schema.Column{Name: "null_blob", Type: &schema.ColumnType{Type: &schema.BinaryType{T: "blob"}, Null: true}},
&schema.Column{Name: "notnull_blob", Type: &schema.ColumnType{Type: &schema.BinaryType{T: "blob"}}, Default: &schema.Literal{V: "'blob'"}},
)
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 9)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// Scan records from the table to ensure correctness of
// the rows transferring.
rows, err := t.db.Query("SELECT id, notnull_int FROM users")
require.NoError(t, err)
require.True(t, rows.Next())
var v [2]int
require.NoError(t, rows.Scan(&v[0], &v[1]))
require.Equal(t, [2]int{1, 1}, v)
require.True(t, rows.Next())
require.NoError(t, rows.Scan(&v[0], &v[1]))
require.Equal(t, [2]int{2, 1}, v)
require.False(t, rows.Next())
require.NoError(t, rows.Close())
})
}
func TestSQLite_ColumnInt(t *testing.T) {
t.Run("ChangeTypeNull", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
usersT.Columns[0].Type.Null = true
usersT.Columns[0].Type.Type = &schema.FloatType{T: "real"}
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
require.Equal(t, schema.ChangeNull|schema.ChangeType, changes[0].(*schema.ModifyColumn).Change)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
})
t.Run("ChangeDefault", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}, Default: &schema.Literal{V: "1"}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
for _, x := range []string{"2", "'3'", "10.1"} {
usersT.Columns[0].Default.(*schema.Literal).V = x
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
_, err := t.db.Exec("INSERT INTO users DEFAULT VALUES")
require.NoError(t, err)
}
rows, err := t.db.Query("SELECT a FROM users")
require.NoError(t, err)
for _, e := range []driver.Value{2, 3, 10.1} {
var v driver.Value
require.True(t, rows.Next())
require.NoError(t, rows.Scan(&v))
require.EqualValues(t, e, v)
}
require.False(t, rows.Next())
require.NoError(t, rows.Close())
})
})
}
func TestSQLite_ForeignKey(t *testing.T) {
t.Run("ChangeAction", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
usersT, postsT := t.users(), t.posts()
t.dropTables(postsT.Name, usersT.Name)
t.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})
ensureNoChange(t, postsT, usersT)
postsT = t.loadPosts()
// The "author_id" constraint. SQLite does not support
// getting the foreign-key constraint names at the moment.
fk := postsT.ForeignKeys[0]
fk.OnUpdate = schema.SetNull
fk.OnDelete = schema.Cascade
changes := t.diff(t.loadPosts(), postsT)
require.Len(t, changes, 1)
modifyF, ok := changes[0].(*schema.ModifyForeignKey)
require.True(t, ok)
require.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)
t.migrate(&schema.ModifyTable{T: postsT, Changes: changes})
ensureNoChange(t, postsT, usersT)
})
})
t.Run("UnsetNull", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
usersT, postsT := t.users(), t.posts()
t.dropTables(postsT.Name, usersT.Name)
fk := postsT.ForeignKeys[0]
fk.OnDelete = schema.SetNull
fk.OnUpdate = schema.SetNull
t.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})
ensureNoChange(t, postsT, usersT)
postsT = t.loadPosts()
c, ok := postsT.Column("author_id")
require.True(t, ok)
c.Type.Null = false
fk = postsT.ForeignKeys[0]
fk.OnUpdate = schema.NoAction
fk.OnDelete = schema.NoAction
changes := t.diff(t.loadPosts(), postsT)
require.Len(t, changes, 2)
modifyC, ok := changes[0].(*schema.ModifyColumn)
require.True(t, ok)
require.True(t, modifyC.Change == schema.ChangeNull)
modifyF, ok := changes[1].(*schema.ModifyForeignKey)
require.True(t, ok)
require.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)
t.migrate(&schema.ModifyTable{T: postsT, Changes: changes})
ensureNoChange(t, postsT, usersT)
})
})
t.Run("AddDrop", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
usersT := t.users()
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
ensureNoChange(t, usersT)
// Add foreign key.
usersT.Columns = append(usersT.Columns, &schema.Column{
Name: "spouse_id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
})
usersT.ForeignKeys = append(usersT.ForeignKeys, &schema.ForeignKey{
Symbol: "spouse_id",
Table: usersT,
Columns: usersT.Columns[len(usersT.Columns)-1:],
RefTable: usersT,
RefColumns: usersT.Columns[:1],
OnDelete: schema.NoAction,
})
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
addC, ok := changes[0].(*schema.AddColumn)
require.True(t, ok)
require.Equal(t, "spouse_id", addC.C.Name)
addF, ok := changes[1].(*schema.AddForeignKey)
require.True(t, ok)
require.Equal(t, "spouse_id", addF.F.Symbol)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// Drop foreign keys.
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
usersT.ForeignKeys = usersT.ForeignKeys[:len(usersT.ForeignKeys)-1]
changes = t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
})
}
func TestSQLite_HCL(t *testing.T) {
full := `
schema "main" {
}
table "users" {
schema = schema.main
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
table "posts" {
schema = schema.main
column "id" {
type = int
}
column "author_id" {
type = int
}
foreign_key "author" {
columns = [
table.posts.column.author_id,
]
ref_columns = [
table.users.column.id,
]
}
primary_key {
columns = [table.users.column.id]
}
}
`
empty := `
schema "main" {
}
`
liteRun(t, func(t *liteTest) {
testHCLIntegration(t, full, empty)
})
}
func TestSQLite_DefaultsHCL(t *testing.T) {
n := "atlas_defaults"
liteRun(t, func(t *liteTest) {
ddl := `
create table atlas_defaults
(
string varchar(255) default "hello_world",
quoted varchar(100) default 'never say "never"',
d date default current_timestamp,
n integer default 0x100
)
`
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
spec, err := sqlite.MarshalHCL(realm.Schemas[0])
require.NoError(t, err)
var s schema.Schema
err = sqlite.EvalHCLBytes(spec, &s, nil)
require.NoError(t, err)
t.dropTables(n)
t.applyHcl(string(spec))
ensureNoChange(t, realm.Schemas[0].Tables[0])
})
}
func TestSQLite_CLI(t *testing.T) {
h := `
schema "main" {
}
table "users" {
schema = schema.main
column "id" {
type = int
}
}`
t.Run("InspectFromEnv", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
env := fmt.Sprintf(`
env "hello" {
url = "%s"
src = "./schema.hcl"
}
`, t.url(""))
wd, _ := os.Getwd()
envfile := filepath.Join(wd, "atlas.hcl")
err := os.WriteFile(envfile, []byte(env), 0600)
t.Cleanup(func() {
os.Remove(envfile)
})
require.NoError(t, err)
testCLISchemaInspectEnv(t, h, "hello", sqlite.EvalHCL)
})
})
t.Run("SchemaInspect", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
testCLISchemaInspect(t, h, t.url(""), sqlite.EvalHCL)
})
})
t.Run("SchemaApply", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
testCLISchemaApply(t, h, t.url(""), "--dev-url", t.dev())
})
})
t.Run("SchemaApplyWithVars", func(t *testing.T) {
h := `
variable "tenant" {
type = string
}
schema "tenant" {
name = var.tenant
}
table "users" {
schema = schema.tenant
column "id" {
type = int
}
}
`
liteRun(t, func(t *liteTest) {
testCLISchemaApply(t, h, t.url(""), "--var", "tenant=main", "--dev-url", t.dev())
})
})
t.Run("SchemaApplyDryRun", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
testCLISchemaApplyDry(t, h, t.url(""))
})
})
t.Run("SchemaDiffRun", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
testCLISchemaDiff(t, t.url(""))
})
})
t.Run("SchemaApplyAutoApprove", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
testCLISchemaApplyAutoApprove(t, h, t.url(""))
})
})
}
func TestSQLite_Sanity(t *testing.T) {
n := "atlas_types_sanity"
ddl := `
create table atlas_types_sanity
(
"tInteger" integer(10) default 100 null,
"tInt" int(10) default 100 null,
"tTinyIny" tinyint(10) default 100 null,
"tSmallInt" smallint(10) default 100 null,
"tMediumInt" mediumint(10) default 100 null,
"tIntegerBigInt" bigint(10) default 100 null,
"tUnsignedBigInt" unsigned big int(10) default 100 null,
"tInt2" int2(10) default 100 null,
"tInt8" int8(10) default 100 null,
"tReal" real(10) default 100 null,
"tDouble" double(10) default 100 null,
"tDoublePrecision" double precision(10) default 100 null,
"tFloat" float(10) default 100 null,
"tText" text(10) default 'I am Text' not null,
"tCharacter" character(10) default 'I am Text' not null,
"tVarchar" varchar(10) default 'I am Text' not null,
"tVaryingCharacter" varying character(10) default 'I am Text' not null,
"tNchar" nchar(10) default 'I am Text' not null,
"tNativeCharacter" native character(10) default 'I am Text' not null,
"tNVarChar" nvarchar(10) default 'I am Text' not null,
"tClob" clob(10) default 'I am Text' not null,
"tBlob" blob(10) default 'A' not null,
"tNumeric" numeric(10) default 100 not null,
"tDecimal" decimal(10,5) default 100 not null,
"tBoolean" boolean default false not null,
"tDate" date default 'now()' not null ,
"tDatetime" datetime default 'now()' not null
);
`
liteRun(t, func(t *liteTest) {
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
require.Len(t, realm.Schemas, 1)
ts, ok := realm.Schemas[0].Table(n)
require.True(t, ok)
expected := schema.Table{
Name: n,
Schema: realm.Schemas[0],
Attrs: ts.Attrs,
Columns: []*schema.Column{
{
Name: "tInteger",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer", Unsigned: false}, Raw: "integer(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int", Unsigned: false}, Raw: "int(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tTinyIny",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "tinyint", Unsigned: false}, Raw: "tinyint(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tSmallInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "smallint", Unsigned: false}, Raw: "smallint(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tMediumInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "mediumint", Unsigned: false}, Raw: "mediumint(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tIntegerBigInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false}, Raw: "bigint(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tUnsignedBigInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "unsigned big int", Unsigned: false}, Raw: "unsigned big int(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tInt2",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int2", Unsigned: false}, Raw: "int2(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tInt8",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int8", Unsigned: false}, Raw: "int8(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tReal",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "real", Precision: 0}, Raw: "real(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tDouble",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "double", Precision: 0}, Raw: "double(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tDoublePrecision",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "double precision", Precision: 0}, Raw: "double precision(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tFloat",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "float", Precision: 0}, Raw: "float(10)", Null: true},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tText",
Type: &schema.ColumnType{Type: &schema.StringType{T: "text", Size: 10}, Raw: "text(10)", Null: false},
Default: &schema.Literal{
V: "'I am Text'",
},
},
{
Name: "tCharacter",
Type: &schema.ColumnType{Type: &schema.StringType{T: "character", Size: 10}, Raw: "character(10)", Null: false},
Default: &schema.Literal{
V: "'I am Text'",
},
},
{
Name: "tVarchar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar", Size: 10}, Raw: "varchar(10)", Null: false},
Default: &schema.Literal{
V: "'I am Text'",
},
},
{
Name: "tVaryingCharacter",
Type: &schema.ColumnType{Type: &schema.StringType{T: "varying character", Size: 10}, Raw: "varying character(10)", Null: false},
Default: &schema.Literal{
V: "'I am Text'",
},
},
{
Name: "tNchar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "nchar", Size: 10}, Raw: "nchar(10)", Null: false},
Default: &schema.Literal{
V: "'I am Text'",
},
},
{
Name: "tNativeCharacter",
Type: &schema.ColumnType{Type: &schema.StringType{T: "native character", Size: 10}, Raw: "native character(10)", Null: false},
Default: &schema.Literal{
V: "'I am Text'",
},
},
{
Name: "tNVarChar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "nvarchar", Size: 10}, Raw: "nvarchar(10)", Null: false},
Default: &schema.Literal{
V: "'I am Text'",
},
},
{
Name: "tClob",
Type: &schema.ColumnType{Type: &schema.StringType{T: "clob", Size: 10}, Raw: "clob(10)", Null: false},
Default: &schema.Literal{
V: "'I am Text'",
},
},
{
Name: "tBlob",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "blob"}, Raw: "blob(10)", Null: false},
Default: &schema.Literal{
V: "'A'",
},
},
{
Name: "tNumeric",
Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 10}, Raw: "numeric(10)", Null: false},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tDecimal",
Type: &schema.ColumnType{Type: &schema.DecimalType{T: "decimal", Precision: 10, Scale: 5}, Raw: "decimal(10,5)", Null: false},
Default: &schema.Literal{
V: "100",
},
},
{
Name: "tBoolean",
Type: &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}, Raw: "boolean", Null: false},
Default: &schema.Literal{
V: "false",
},
},
{
Name: "tDate",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "date"}, Raw: "date", Null: false},
Default: &schema.Literal{
V: "'now()'",
},
},
{
Name: "tDatetime",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "datetime"}, Raw: "datetime", Null: false},
Default: &schema.Literal{
V: "'now()'",
},
},
},
}
require.EqualValues(t, &expected, ts)
})
t.Run("ImplicitIndexes", func(t *testing.T) {
liteRun(t, func(t *liteTest) {
testImplicitIndexes(t, t.db)
})
})
}
func (t *liteTest) driver() migrate.Driver {
return t.drv
}
func (t *liteTest) revisionsStorage() migrate.RevisionReadWriter {
return t.rrw
}
func (t *liteTest) dropSchemas(...string) {}
func (t *liteTest) applyHcl(spec string) {
realm := t.loadRealm()
var desired schema.Schema
err := sqlite.EvalHCLBytes([]byte(spec), &desired, nil)
require.NoError(t, err)
existing := realm.Schemas[0]
diff, err := t.drv.SchemaDiff(existing, &desired)
require.NoError(t, err)
err = t.drv.ApplyChanges(context.Background(), diff)
require.NoError(t, err)
}
func (t *liteTest) loadRealm() *schema.Realm {
r, err := t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{
Schemas: []string{"main"},
Mode: schema.InspectSchemas | schema.InspectTables,
})
require.NoError(t, err)
return r
}
func (t *liteTest) loadUsers() *schema.Table {
return t.loadTable("users")
}
func (t *liteTest) loadPosts() *schema.Table {
return t.loadTable("posts")
}
func (t *liteTest) loadTable(name string) *schema.Table {
realm := t.loadRealm()
require.Len(t, realm.Schemas, 1)
table, ok := realm.Schemas[0].Table(name)
require.True(t, ok)
return table
}
func (t *liteTest) users() *schema.Table {
usersT := &schema.Table{
Name: "users",
Schema: t.realm().Schemas[0],
Columns: []*schema.Column{
{
Name: "id",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}},
},
{
Name: "x",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}},
},
},
}
usersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}
return usersT
}
func (t *liteTest) posts() *schema.Table {
usersT := t.users()
postsT := &schema.Table{
Name: "posts",
Schema: t.realm().Schemas[0],
Columns: []*schema.Column{
{
Name: "id",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}},
Attrs: []schema.Attr{&postgres.Identity{}},
},
{
Name: "author_id",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Null: true},
Default: &schema.RawExpr{X: "10"},
},
{
Name: "ctime",
Type: &schema.ColumnType{Raw: "timestamp", Type: &schema.TimeType{T: "timestamp"}},
Default: &schema.RawExpr{
X: "CURRENT_TIMESTAMP",
},
},
},
Attrs: []schema.Attr{
&schema.Comment{Text: "posts comment"},
},
}
postsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}
postsT.Indexes = []*schema.Index{
{Name: "author_id", Parts: []*schema.IndexPart{{C: postsT.Columns[1]}}},
{Name: "id_author_id_unique", Unique: true, Parts: []*schema.IndexPart{{C: postsT.Columns[1]}, {C: postsT.Columns[0]}}},
}
postsT.ForeignKeys = []*schema.ForeignKey{
{Symbol: "author_id", Table: postsT, Columns: postsT.Columns[1:2], RefTable: usersT, RefColumns: usersT.Columns[:1], OnDelete: schema.NoAction},
}
return postsT
}
func (t *liteTest) realm() *schema.Realm {
r := &schema.Realm{
Schemas: []*schema.Schema{
{
Name: "main",
Attrs: []schema.Attr{
&sqlite.File{Name: t.file},
},
},
},
}
r.Schemas[0].Realm = r
return r
}
func (t *liteTest) diff(t1, t2 *schema.Table) []schema.Change {
changes, err := t.drv.TableDiff(t1, t2)
require.NoError(t, err)
return changes
}
func (t *liteTest) migrate(changes ...schema.Change) {
err := t.drv.ApplyChanges(context.Background(), changes)
require.NoError(t, err)
}
func (t *liteTest) dropTables(names ...string) {
t.Cleanup(func() {
for i := range names {
_, err := t.db.Exec("DROP TABLE IF EXISTS " + names[i])
require.NoError(t.T, err, "drop tables %q", names[i])
}
})
}
func (t *liteTest) url(_ string) string {
return fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", t.file)
}
func (t *liteTest) dev() string {
return fmt.Sprintf("sqlite://%s?mode=memory&_fk=1", t.Name())
}
func (t *liteTest) applyRealmHcl(spec string) {
t.applyHcl(spec)
}
================================================
FILE: internal/integration/testdata/migrations/mysql/1_initial.sql
================================================
CREATE SCHEMA IF NOT EXISTS `bc_test`;
CREATE TABLE `bc_test`.`bc_tbl` (`col` INTEGER NULL);
================================================
FILE: internal/integration/testdata/migrations/mysql/atlas.sum
================================================
h1:FT0VjrL64KJmuOe1Dq4dpbG/50Kwn0lZqfopa6BhJM8=
1_initial.sql h1:bWUYLjb0oiGQHf45Q08aKFKxVZ3pZBArJnSmuGBw9X4=
================================================
FILE: internal/integration/testdata/migrations/mysqlock/1.sql
================================================
CREATE TABLE `t1` (`id` int);
CREATE TABLE `t2` (`id` int);
select sleep(0.1);
CREATE TABLE `t3` (`id` int);
CREATE TABLE `t4` (`id` int);
CREATE TABLE `t5` (`id` int);
select sleep(0.1);
CREATE TABLE `t6` (`id` int);
================================================
FILE: internal/integration/testdata/migrations/mysqlock/2.sql
================================================
ALTER TABLE `t1` ADD COLUMN `c1` varchar(255) DEFAULT 'name';
ALTER TABLE `t2` ADD COLUMN `c1` varchar(255) DEFAULT 'name';
select sleep(0.1);
ALTER TABLE `t3` ADD COLUMN `c1` varchar(255) DEFAULT 'name';
ALTER TABLE `t4` ADD COLUMN `c1` varchar(255) DEFAULT 'name';
select sleep(0.1);
ALTER TABLE `t5` ADD COLUMN `c1` varchar(255) DEFAULT 'name';
ALTER TABLE `t6` ADD COLUMN `c1` varchar(255) DEFAULT 'name';
ALTER TABLE `t1` ADD COLUMN `c2` varchar(255) DEFAULT 'name';
ALTER TABLE `t2` ADD COLUMN `c2` varchar(255) DEFAULT 'name';
select sleep(0.1);
ALTER TABLE `t3` ADD COLUMN `c2` varchar(255) DEFAULT 'name';
ALTER TABLE `t4` ADD COLUMN `c2` varchar(255) DEFAULT 'name';
select sleep(0.1);
ALTER TABLE `t5` ADD COLUMN `c2` varchar(255) DEFAULT 'name';
ALTER TABLE `t6` ADD COLUMN `c2` varchar(255) DEFAULT 'name';
================================================
FILE: internal/integration/testdata/migrations/mysqlock/3.sql
================================================
CREATE TABLE `t7` (`id` int);
select sleep(0.1);
CREATE TABLE `t8` (`id` int);
CREATE TABLE `t9` (`id` int);
================================================
FILE: internal/integration/testdata/migrations/mysqlock/atlas.sum
================================================
h1:XiFkhbkD+gUR/ry9+AVfyLW4X/tYaVUHFul5q0Kvtpo=
1.sql h1:+HoZslM3E59DllQlUXd5TFnPw+9de9IBNQEYdn77f7c=
2.sql h1:OliSiXPsLoVoWixWDC/yBJUtjrxnMMm+hjCf2Sz66Rk=
3.sql h1:Gb5M9ibe0COwTBrb08v/4VuWXxJ55+D2lSLXHLVa/Po=
================================================
FILE: internal/integration/testdata/migrations/postgres/1_initial.sql
================================================
CREATE SCHEMA IF NOT EXISTS "bc_test";
CREATE TABLE "bc_test"."bc_tbl" ("col" INTEGER NULL);
================================================
FILE: internal/integration/testdata/migrations/postgres/atlas.sum
================================================
h1:80V3wCzovMg2ot2hR0arbEjEfMfKWDeQNrXZJbFPF10=
1_initial.sql h1:53poyM34ShPWCVU41ldi4d9LUrzqPiQfBdEq//yH4Jo=
================================================
FILE: internal/integration/testdata/mysql/autoincrement.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
# Setup a custom AUTO_INCREMENT initial value.
apply 2.hcl
cmpshow users 2.sql
# Increase the AUTO_INCREMENT value.
apply 3.hcl
cmpshow users 3.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "id" {
null = false
type = bigint
auto_increment = true
}
primary_key {
columns = [column.id]
}
}
-- 1.sql --
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
)
-- mysql8/1.sql --
CREATE TABLE `users` (
`id` bigint NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
)
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "id" {
null = false
type = bigint
auto_increment = true
}
primary_key {
columns = [column.id]
}
auto_increment = 1000
}
-- 2.sql --
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) AUTO_INCREMENT=1000
-- mysql8/2.sql --
CREATE TABLE `users` (
`id` bigint NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) AUTO_INCREMENT=1000
-- 3.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "id" {
null = false
type = bigint
auto_increment = true
}
primary_key {
columns = [column.id]
}
auto_increment = 2000
}
-- 3.sql --
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) AUTO_INCREMENT=2000
-- mysql8/3.sql --
CREATE TABLE `users` (
`id` bigint NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) AUTO_INCREMENT=2000
================================================
FILE: internal/integration/testdata/mysql/check-maria.txtar
================================================
only maria107
atlas schema inspect --url file://schema.sql --dev-url URL > got.hcl
cmp expected.hcl got.hcl
atlas schema inspect --url file://schema.sql --dev-url URL --format '{{ sql . " " }}' > got.sql
cmp expected.sql got.sql
-- schema.sql --
CREATE TABLE t1(
buf json,
name varchar(20) CHECK(name in ('a', 'b', 'c')),
age int CHECK(age > 0),
-- MariaDB check constraint names are not unique.
CONSTRAINT `check1` CHECK (name <> 'a' or age > 10)
);
CREATE TABLE t2(
buf json,
name varchar(20) CHECK(name in ('a', 'b', 'c')),
age int CHECK(age > 1),
-- MariaDB check constraint names are not unique.
CONSTRAINT `check1` CHECK (name <> 'a' or age > 10)
);
-- expected.hcl --
table "t1" {
schema = schema.script_check_maria
column "buf" {
null = true
type = json
}
column "name" {
null = true
type = varchar(20)
}
column "age" {
null = true
type = int
}
check "age" {
expr = "`age` > 0"
}
check "check1" {
expr = "`name` <> 'a' or `age` > 10"
}
check "name" {
expr = "`name` in ('a','b','c')"
}
}
table "t2" {
schema = schema.script_check_maria
column "buf" {
null = true
type = json
}
column "name" {
null = true
type = varchar(20)
}
column "age" {
null = true
type = int
}
check "age" {
expr = "`age` > 1"
}
check "check1" {
expr = "`name` <> 'a' or `age` > 10"
}
check "name" {
expr = "`name` in ('a','b','c')"
}
}
schema "script_check_maria" {
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
-- expected.sql --
-- Create "t1" table
CREATE TABLE `t1` (
`buf` json NULL,
`name` varchar(20) NULL,
`age` int NULL,
CONSTRAINT `age` CHECK (`age` > 0),
CONSTRAINT `check1` CHECK (`name` <> 'a' or `age` > 10),
CONSTRAINT `name` CHECK (`name` in ('a','b','c'))
) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
-- Create "t2" table
CREATE TABLE `t2` (
`buf` json NULL,
`name` varchar(20) NULL,
`age` int NULL,
CONSTRAINT `age` CHECK (`age` > 1),
CONSTRAINT `check1` CHECK (`name` <> 'a' or `age` > 10),
CONSTRAINT `name` CHECK (`name` in ('a','b','c'))
) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
================================================
FILE: internal/integration/testdata/mysql/check.txtar
================================================
only mysql8
atlas schema inspect --url file://schema.sql --dev-url URL > got.hcl
cmp expected.hcl got.hcl
atlas schema inspect --url file://schema.sql --dev-url URL --format '{{ sql . " " }}' > got.sql
cmp expected.sql got.sql
atlas migrate diff v1 --to file://schema.sql --dev-url URL --format '{{ sql . " " }}'
cmpmig 0 migration.v1.sql
atlas migrate diff v1-check --to file://schema.sql --dev-url URL --format '{{ sql . " " }}'
stdout 'The migration directory is synced with the desired state, no changes to be made'
atlas migrate diff v2 --to file://schema.v2.sql --dev-url URL --format '{{ sql . " " }}'
cmpmig 1 migration.v2.sql
atlas migrate diff v2-check --to file://schema.v2.sql --dev-url URL --format '{{ sql . " " }}'
stdout 'The migration directory is synced with the desired state, no changes to be made'
atlas migrate diff v3 --to file://schema.v3.sql --dev-url URL --format '{{ sql . " " }}'
cmpmig 2 migration.v3.sql
atlas migrate diff v3 --to file://schema.v3.sql --dev-url URL --format '{{ sql . " " }}'
stdout 'The migration directory is synced with the desired state, no changes to be made'
-- schema.sql --
CREATE TABLE t1(
name varchar(20) CHECK(name in ('a', 'b', 'c')),
age int CHECK(age > 0),
-- MySQL check constraint names are unique in schema level.
CONSTRAINT `t1_check` CHECK (name <> 'a' or age > 10)
);
CREATE TABLE t2(
name varchar(20) CHECK(name in ('a', 'b', 'c')),
age int CHECK(age > 0),
-- MySQL check constraint names are unique in schema level.
CONSTRAINT `t2_check` CHECK (name <> 'a' or age > 10)
);
-- expected.hcl --
table "t1" {
schema = schema.script_check
column "name" {
null = true
type = varchar(20)
}
column "age" {
null = true
type = int
}
check "t1_check" {
expr = "((`name` <> _utf8mb4'a') or (`age` > 10))"
}
check "t1_chk_1" {
expr = "(`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c'))"
}
check "t1_chk_2" {
expr = "(`age` > 0)"
}
}
table "t2" {
schema = schema.script_check
column "name" {
null = true
type = varchar(20)
}
column "age" {
null = true
type = int
}
check "t2_check" {
expr = "((`name` <> _utf8mb4'a') or (`age` > 10))"
}
check "t2_chk_1" {
expr = "(`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c'))"
}
check "t2_chk_2" {
expr = "(`age` > 0)"
}
}
schema "script_check" {
charset = "utf8mb4"
collate = "utf8mb4_0900_ai_ci"
}
-- expected.sql --
-- Create "t1" table
CREATE TABLE `t1` (
`name` varchar(20) NULL,
`age` int NULL,
CONSTRAINT `t1_check` CHECK ((`name` <> _utf8mb4'a') or (`age` > 10)),
CONSTRAINT `t1_chk_1` CHECK (`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c')),
CONSTRAINT `t1_chk_2` CHECK (`age` > 0)
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- Create "t2" table
CREATE TABLE `t2` (
`name` varchar(20) NULL,
`age` int NULL,
CONSTRAINT `t2_check` CHECK ((`name` <> _utf8mb4'a') or (`age` > 10)),
CONSTRAINT `t2_chk_1` CHECK (`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c')),
CONSTRAINT `t2_chk_2` CHECK (`age` > 0)
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- migration.v1.sql --
-- Create "t1" table
CREATE TABLE `t1` (
`name` varchar(20) NULL,
`age` int NULL,
CONSTRAINT `t1_check` CHECK ((`name` <> _utf8mb4'a') or (`age` > 10)),
CONSTRAINT `t1_chk_1` CHECK (`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c')),
CONSTRAINT `t1_chk_2` CHECK (`age` > 0)
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- Create "t2" table
CREATE TABLE `t2` (
`name` varchar(20) NULL,
`age` int NULL,
CONSTRAINT `t2_check` CHECK ((`name` <> _utf8mb4'a') or (`age` > 10)),
CONSTRAINT `t2_chk_1` CHECK (`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c')),
CONSTRAINT `t2_chk_2` CHECK (`age` > 0)
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- schema.v2.sql --
CREATE TABLE t1(
name varchar(20) CHECK(name in ('a', 'b', 'c')),
age int CHECK(age > 0),
-- MySQL check constraint names are unique in schema level.
CONSTRAINT `t1_check` CHECK (name <> 'b' or age > 10)
);
CREATE TABLE t2(
name varchar(20) CHECK(name in ('a', 'b', 'c')),
age int CHECK(age > 0),
-- MySQL check constraint names are unique in schema level.
CONSTRAINT `t2_check` CHECK (name <> 'a' or age > 10)
);
-- migration.v2.sql --
-- Modify "t1" table
ALTER TABLE `t1` DROP CHECK `t1_check`, ADD CONSTRAINT `t1_check` CHECK ((`name` <> _utf8mb4'b') or (`age` > 10));
-- schema.v3.sql --
CREATE TABLE t1(
name varchar(20) CHECK(name in ('a', 'b', 'c')),
age int CHECK(age > 0),
-- MySQL check constraint names are unique in schema level.
CONSTRAINT `t1_check` CHECK (name <> 'b' or age > 10)
);
CREATE TABLE t2(
name varchar(20) CHECK(name in ('a', 'b', 'c')),
age int CHECK(age > 0),
-- MySQL check constraint names are unique in schema level.
CONSTRAINT `t2_check` CHECK (name <> 'b' or age > 10)
);
-- migration.v3.sql --
-- Modify "t2" table
ALTER TABLE `t2` DROP CHECK `t2_check`, ADD CONSTRAINT `t2_check` CHECK ((`name` <> _utf8mb4'b') or (`age` > 10));
================================================
FILE: internal/integration/testdata/mysql/cli-inspect-file.txtar
================================================
only mysql8
# inspect without dev-db will failed
! atlas schema inspect -u file://a.sql
stderr 'Error: --dev-url cannot be empty'
# inspect file to HCL
atlas schema inspect -u file://a.sql --dev-url URL > inspected.hcl
cmp inspected.hcl script_cli_inspect.hcl
# inspect file to SQL
atlas schema inspect -u file://a.sql --dev-url URL --format '{{ sql . }}' > inspected.sql
cmp inspected.sql script_cli_inspect.sql
-- a.sql --
create table users (
id int NOT NULL,
PRIMARY KEY (id)
)
-- script_cli_inspect.hcl --
table "users" {
schema = schema.script_cli_inspect_file
column "id" {
null = false
type = int
}
primary_key {
columns = [column.id]
}
}
schema "script_cli_inspect_file" {
charset = "utf8mb4"
collate = "utf8mb4_0900_ai_ci"
}
-- script_cli_inspect.sql --
-- Create "users" table
CREATE TABLE `users` (`id` int NOT NULL, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
================================================
FILE: internal/integration/testdata/mysql/cli-migrate-apply-datasrc.txtar
================================================
only mysql8
atlas migrate hash
atlas migrate apply --url URL --env dev --var "url=URL" --var "pattern=script_cli_migrate_apply_datasrc"
stdout 'Migrating to version 1 \(1 migrations in total\):'
-- atlas.hcl --
variable "url" {
type = string
}
variable "pattern" {
type = string
}
data "sql" "tenants" {
url = var.url
query = < CREATE TABLE `users` \(`id` bigint NOT NULL AUTO_INCREMENT, `age` bigint NOT NULL, `name` varchar\(255\) NOT NULL, PRIMARY KEY \(`id`\)\) CHARSET utf8mb4 COLLATE utf8mb4_bin;'
stdout '-- migrating version 2'
stdout '-> ALTER TABLE `users` ADD UNIQUE INDEX `age` \(`age`\);'
stdout '-- migrating version 3'
stdout '-> CREATE TABLE `pets` \(`id` bigint NOT NULL AUTO_INCREMENT, `name` varchar\(255\) NOT NULL, PRIMARY KEY \(`id`\)\) CHARSET utf8mb4 COLLATE utf8mb4_bin;'
stdout '-- 3 migrations'
stdout '-- 3 sql statements'
cmpshow users users.sql
cmpshow pets pets.sql
atlas migrate apply --url URL --revisions-schema $db
stdout 'No migration files to execute'
clearSchema
# Apply one by one
atlas migrate apply --url URL --revisions-schema $db 1
stdout 'Migrating to version 1 \(1 migrations in total\):'
cmpshow users users_1.sql
atlas migrate apply --url URL --revisions-schema $db 1
stdout 'Migrating to version 2 from 1 \(1 migrations in total\):'
cmpshow users users.sql
atlas migrate apply --url URL --revisions-schema $db 1
stdout 'Migrating to version 3 from 2 \(1 migrations in total\):'
cmpshow users users.sql
cmpshow pets pets.sql
atlas migrate apply --url URL --revisions-schema $db 1
stdout 'No migration files to execute'
clearSchema
atlas migrate apply --url URL --revisions-schema $db --log '{{ json . }}'
validJSON stdout
stdout '"Driver":"mysql"'
stdout '"Scheme":"mysql"'
stdout '"Dir":"file://migrations"'
stdout '"Target":"3"'
stdout '"Pending":\[{"Name":"1_first.sql","Version":"1","Description":"first"},{"Name":"2_second.sql","Version":"2","Description":"second"},{"Name":"3_third.sql","Version":"3","Description":"third"}\]'
stdout '"Applied":\["CREATE TABLE `users` \(`id` bigint NOT NULL AUTO_INCREMENT, `age` bigint NOT NULL, `name` varchar\(255\) NOT NULL, PRIMARY KEY \(`id`\)\) CHARSET utf8mb4 COLLATE utf8mb4_bin;"\]'
stdout '"Start":"\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.[0-9]'
-- migrations/1_first.sql --
CREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, `age` bigint NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_bin;
-- migrations/2_second.sql --
ALTER TABLE `users` ADD UNIQUE INDEX `age` (`age`);
-- migrations/3_third.sql --
CREATE TABLE `pets` (`id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_bin;
-- users.sql --
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`age` bigint(20) NOT NULL,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `age` (`age`)
)
-- mysql8/users.sql --
CREATE TABLE `users` (
`id` bigint NOT NULL AUTO_INCREMENT,
`age` bigint NOT NULL,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `age` (`age`)
)
-- users_1.sql --
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`age` bigint(20) NOT NULL,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`)
)
-- mysql8/users_1.sql --
CREATE TABLE `users` (
`id` bigint NOT NULL AUTO_INCREMENT,
`age` bigint NOT NULL,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`)
)
-- pets.sql --
CREATE TABLE `pets` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`)
)
-- mysql8/pets.sql --
CREATE TABLE `pets` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`)
)
================================================
FILE: internal/integration/testdata/mysql/cli-migrate-diff-format.txtar
================================================
only maria103
mkdir migrations
# old behavior still works
atlas migrate diff --dev-url URL --to file://1.hcl --dir-format golang-migrate first
cmpmig 0 golang-migrate/1.down.sql
cmpmig 1 golang-migrate/1.up.sql
atlas migrate diff --dev-url URL --to file://2.hcl --dir-format golang-migrate second
cmpmig 2 golang-migrate/2.down.sql
cmpmig 3 golang-migrate/2.up.sql
rm migrations
mkdir migrations
atlas migrate diff --dev-url URL --to file://1.hcl --dir file://migrations?format=golang-migrate first
cmpmig 0 golang-migrate/1.down.sql
cmpmig 1 golang-migrate/1.up.sql
atlas migrate diff --dev-url URL --to file://2.hcl --dir file://migrations?format=golang-migrate second
cmpmig 2 golang-migrate/2.down.sql
cmpmig 3 golang-migrate/2.up.sql
rm migrations
mkdir migrations
atlas migrate diff --dev-url URL --to file://1.hcl --dir file://migrations?format=goose first
cmpmig 0 goose/1.sql
atlas migrate diff --dev-url URL --to file://2.hcl --dir file://migrations?format=goose second
cmpmig 1 goose/2.sql
rm migrations
mkdir migrations
atlas migrate diff --dev-url URL --to file://1.hcl --dir file://migrations?format=dbmate first
cmpmig 0 dbmate/1.sql
atlas migrate diff --dev-url URL --to file://2.hcl --dir file://migrations?format=dbmate second
cmpmig 1 dbmate/2.sql
rm migrations
mkdir migrations
atlas migrate diff --dev-url URL --to file://1.hcl --dir file://migrations?format=flyway first
cmpmig 0 flyway/U1.sql
cmpmig 1 flyway/V1.sql
atlas migrate diff --dev-url URL --to file://2.hcl --dir file://migrations?format=flyway second
cmpmig 1 flyway/U2.sql
cmpmig 3 flyway/V2.sql
rm migrations
mkdir migrations
atlas migrate diff --dev-url URL --to file://1.hcl --dir file://migrations?format=liquibase first
cmpmig 0 liquibase/1.sql
atlas migrate diff --dev-url URL --to file://2.hcl --dir file://migrations?format=liquibase second
cmpmig 1 liquibase/2.sql
-- golang-migrate/1.up.sql --
-- create "users" table
CREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
-- golang-migrate/1.down.sql --
-- reverse: create "users" table
DROP TABLE `users`;
-- golang-migrate/2.up.sql --
-- modify "users" table
ALTER TABLE `users` ADD COLUMN `email` varchar(100) NULL;
-- golang-migrate/2.down.sql --
-- reverse: modify "users" table
ALTER TABLE `users` DROP COLUMN `email`;
-- goose/1.sql --
-- +goose Up
-- create "users" table
CREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
-- +goose Down
-- reverse: create "users" table
DROP TABLE `users`;
-- goose/2.sql --
-- +goose Up
-- modify "users" table
ALTER TABLE `users` ADD COLUMN `email` varchar(100) NULL;
-- +goose Down
-- reverse: modify "users" table
ALTER TABLE `users` DROP COLUMN `email`;
-- dbmate/1.sql --
-- migrate:up
-- create "users" table
CREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
-- migrate:down
-- reverse: create "users" table
DROP TABLE `users`;
-- dbmate/2.sql --
-- migrate:up
-- modify "users" table
ALTER TABLE `users` ADD COLUMN `email` varchar(100) NULL;
-- migrate:down
-- reverse: modify "users" table
ALTER TABLE `users` DROP COLUMN `email`;
-- flyway/V1.sql --
-- create "users" table
CREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
-- flyway/U1.sql --
-- reverse: create "users" table
DROP TABLE `users`;
-- flyway/V2.sql --
-- modify "users" table
ALTER TABLE `users` ADD COLUMN `email` varchar(100) NULL;
-- flyway/U2.sql --
-- reverse: modify "users" table
ALTER TABLE `users` DROP COLUMN `email`;
-- liquibase/1.sql --
--liquibase formatted sql
--changeset atlas:0-0
--comment: create "users" table
CREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
--rollback: DROP TABLE `users`;
-- liquibase/2.sql --
--liquibase formatted sql
--changeset atlas:0-0
--comment: modify "users" table
ALTER TABLE `users` ADD COLUMN `email` varchar(100) NULL;
--rollback: ALTER TABLE `users` DROP COLUMN `email`;
-- 1.hcl --
schema "script_cli_migrate_diff_format" {}
table "users" {
schema = schema.script_cli_migrate_diff_format
column "id" {
null = false
type = bigint
auto_increment = true
}
primary_key {
columns = [column.id]
}
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
-- 2.hcl --
schema "script_cli_migrate_diff_format" {}
table "users" {
schema = schema.script_cli_migrate_diff_format
column "id" {
null = false
type = bigint
auto_increment = true
}
column "email" {
null = true
type = varchar(100)
}
primary_key {
columns = [column.id]
}
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
================================================
FILE: internal/integration/testdata/mysql/cli-migrate-diff-mode-normalized.txtar
================================================
only mysql
atlas migrate hash
# Migrate diff wants to drop the unique index.
atlas migrate diff --dev-url URL --to file://./schema.sql
! stdout 'no changes'
cmpmig 1 expected.sql
-- migrations/1.sql --
CREATE TABLE `ref` (
`id` bigint NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) CHARSET utf8mb4 COLLATE utf8mb4_bin;
CREATE TABLE `tbl` (
`ref_id` bigint NOT NULL,
UNIQUE INDEX `u_ref_id` (`ref_id`), -- expected to be dropped
INDEX `ref_id` (`ref_id`),
FOREIGN KEY (`ref_id`) REFERENCES `ref` (`id`)
) CHARSET utf8mb4 COLLATE utf8mb4_bin;
-- schema.sql --
CREATE TABLE `ref` (
`id` bigint NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) CHARSET utf8mb4 COLLATE utf8mb4_bin;
CREATE TABLE `tbl` (
`ref_id` bigint NOT NULL,
INDEX `ref_id` (`ref_id`),
FOREIGN KEY (`ref_id`) REFERENCES `ref` (`id`)
) CHARSET utf8mb4 COLLATE utf8mb4_bin;
-- expected.sql --
-- Modify "tbl" table
ALTER TABLE `tbl` DROP INDEX `u_ref_id`;
================================================
FILE: internal/integration/testdata/mysql/cli-migrate-diff.txtar
================================================
only maria107 maria102
exec mkdir migrations
! atlas migrate diff --to file://1.hcl --dir file://migrations
stderr '"dev-url" not set'
! atlas migrate diff --dev-url mysql://devdb --dir file://migrations
stderr '"to" not set'
atlas migrate diff --dev-url URL --to file://./1.hcl first
cmpmig 0 1.sql
atlas migrate diff --dev-url URL --to file://./2.hcl second
cmpmig 1 2.sql
# Clean migration directory and run diff with a custom qualifier.
exec rm -rf migrations
atlas migrate diff --dev-url URL --to file://./1.hcl --qualifier test first
cmpmig 0 1-qualifier.sql
-- 1.hcl --
schema "script_cli_migrate_diff" {}
table "users" {
schema = schema.script_cli_migrate_diff
column "id" {
null = false
type = bigint
auto_increment = true
}
primary_key {
columns = [column.id]
}
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
-- 1.sql --
-- Create "users" table
CREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
-- 1-qualifier.sql --
-- Create "users" table
CREATE TABLE `test`.`users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
-- 2.hcl --
schema "script_cli_migrate_diff" {}
table "users" {
schema = schema.script_cli_migrate_diff
column "id" {
null = false
type = bigint
auto_increment = true
}
column "create_time" {
null = false
type = timestamp(6)
default = sql("CURRENT_TIMESTAMP(6)")
}
primary_key {
columns = [column.id]
}
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
-- 2.sql --
-- Modify "users" table
ALTER TABLE `users` ADD COLUMN `create_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6);
-- maria102/2.sql --
-- Modify "users" table
ALTER TABLE `users` ADD COLUMN `create_time` timestamp(6) NOT NULL DEFAULT (current_timestamp(6));
-- maria107/2.sql --
-- Modify "users" table
ALTER TABLE `users` ADD COLUMN `create_time` timestamp(6) NOT NULL DEFAULT (current_timestamp(6));
================================================
FILE: internal/integration/testdata/mysql/cli-project-schemas.txtar
================================================
atlas schema apply --env local --auto-approve > out.txt
exec cat out.txt
stdout 'CREATE TABLE `script_cli_project_schemas`'
-- 1.hcl --
schema "script_cli_project_schemas" {
}
table "users" {
schema = schema.script_cli_project_schemas
column "id" {
type = bigint
null = false
}
}
-- atlas.hcl --
env "local" {
url = "URL"
src = "./1.hcl"
schemas = ["script_cli_project_schemas"]
}
-- expected.sql --
CREATE TABLE `users` (
`id` bigint NOT NULL
)
-- 0.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
================================================
FILE: internal/integration/testdata/mysql/cli-project-url-escape.txtar
================================================
only mysql8
execsql 'CREATE USER IF NOT EXISTS "a8m"@"%" IDENTIFIED BY "&pass?"'
execsql 'GRANT ALL PRIVILEGES ON *.* TO "a8m"@"%" WITH GRANT OPTION'
atlas schema inspect --env local > got.txt
cmp got.txt want.txt
! atlas schema inspect --env failed
stderr 'invalid port ":&pass" after host'
execsql 'DROP USER "a8m"@"%"'
-- atlas.hcl --
variable "pass" {
type = string
default = "&pass?"
}
locals {
escaped_pass = urlescape(var.pass)
}
env "local" {
url = "mysql://a8m:${local.escaped_pass}@localhost:3308/script_cli_project_url_escape"
}
env "failed" {
url = "mysql://a8m:${var.pass}@localhost:3308/script_cli_project_url_escape"
}
-- want.txt --
schema "script_cli_project_url_escape" {
charset = "utf8mb4"
collate = "utf8mb4_0900_ai_ci"
}
================================================
FILE: internal/integration/testdata/mysql/cli-schema-apply-datasrc.txtar
================================================
only mysql8
atlas schema apply --auto-approve --url URL --env dev --var "url=URL" --var "pattern=script_cli_schema_apply_datasrc"
stdout '\{"Applied":\["CREATE TABLE `users` \(\\n `id` int NOT NULL\\n\);*"\],"Tenant":"script_cli_schema_apply_datasrc"\}'
-- schema.hcl --
variable "tenant" {
type = string
}
schema "test" {
name = var.tenant
}
table "users" {
schema = schema.test
column "id" {
type = int
}
}
-- atlas.hcl --
variable "url" {
type = string
}
variable "pattern" {
type = string
}
data "sql" "tenants" {
url = var.url
query = </1.sql' (version, defines
# the database version), and in case it was found, it will use it instead.
cmpshow users 1.sql
# Apply schema "2.hcl" on the updated database.
apply 2.hcl
# Compare database with 2.sql.
cmpshow users 2.sql
# Apply schema "1.hcl" should migrate database to previous state.
apply 1.hcl
cmpshow users 1.sql
# Drop table.
apply 0.hcl
! exist users
# Below files represent HCL and SQL. File names defined their index in
# execution order. 1.hcl is executed first, 2.hcl executed second, etc.
-- 1.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
-- 1.sql --
CREATE TABLE `users` (
`id` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
-- mysql8/1.sql --
CREATE TABLE `users` (
`id` int NOT NULL,
PRIMARY KEY (`id`)
)
-- 2.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "id" {
type = int
}
column "name" {
type = text
}
primary_key {
columns = [table.users.column.id]
}
}
-- 2.sql --
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`name` text NOT NULL,
PRIMARY KEY (`id`)
)
-- mysql8/2.sql --
CREATE TABLE `users` (
`id` int NOT NULL,
`name` text NOT NULL,
PRIMARY KEY (`id`)
)
-- 0.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
================================================
FILE: internal/integration/testdata/mysql/column-bit.txtar
================================================
apply 1.hcl
cmpshow t 1.sql
-- 1.hcl --
schema "$db" {}
table "t" {
schema = schema.$db
column "c1" {
type = bit
}
column "c2" {
type = bit(1)
}
column "c3" {
type = bit(64)
}
}
-- 1.sql --
CREATE TABLE `t` (
`c1` bit(1) NOT NULL,
`c2` bit(1) NOT NULL,
`c3` bit(64) NOT NULL
)
================================================
FILE: internal/integration/testdata/mysql/column-bool.txtar
================================================
# Each test runs on a clean database.
apply 1.hcl
cmpshow users 1.sql
# "bool", "boolean" and "tinyint(1)" are equal.
synced 2.hcl
# Changing "tinyint(1)" to "tinyint" should cause a schema change.
apply 3.hcl
cmpshow users 3.sql
synced 3.hcl
-- 1.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "a" {
type = bool
}
column "b" {
type = boolean
}
column "c" {
type = tinyint(1)
}
}
-- 1.sql --
CREATE TABLE `users` (
`a` tinyint(1) NOT NULL,
`b` tinyint(1) NOT NULL,
`c` tinyint(1) NOT NULL
)
-- 2.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "a" {
type = boolean
}
column "b" {
type = tinyint(1)
}
column "c" {
type = bool
}
}
-- 3.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "a" {
type = boolean
}
column "b" {
type = tinyint
}
column "c" {
type = bool
}
}
-- 3.sql --
CREATE TABLE `users` (
`a` tinyint(1) NOT NULL,
`b` tinyint(4) NOT NULL,
`c` tinyint(1) NOT NULL
)
-- mysql8/3.sql --
CREATE TABLE `users` (
`a` tinyint(1) NOT NULL,
`b` tinyint NOT NULL,
`c` tinyint(1) NOT NULL
)
================================================
FILE: internal/integration/testdata/mysql/column-charset.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
# Dropping the default COLLATE from the HCL does not have any effect.
apply 2.hcl
cmpshow users 1.sql
# Changing the default COLLATE to hebrew_bin.
apply 3.hcl
cmpshow users 3.sql
# Dropping custom COLLATE reverts to the default.
apply 4.hcl
cmpshow users 1.sql
# Dropping CHARSET and COLLATE.
apply 5.hcl
cmpshow users 5.sql
-- 1.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "name" {
type = varchar(255)
charset = "hebrew"
collate = "hebrew_general_ci"
}
charset = "$charset"
collate = "$collate"
}
-- 1.sql --
CREATE TABLE `users` (
`name` varchar(255) CHARACTER SET hebrew NOT NULL
)
-- maria107/1.sql --
CREATE TABLE `users` (
`name` varchar(255) CHARACTER SET hebrew COLLATE hebrew_general_ci NOT NULL
)
-- mysql8/1.sql --
CREATE TABLE `users` (
`name` varchar(255) CHARACTER SET hebrew COLLATE hebrew_general_ci NOT NULL
)
-- 2.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "name" {
type = varchar(255)
charset = "hebrew"
}
charset = "$charset"
collate = "$collate"
}
-- 3.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "name" {
type = varchar(255)
charset = "hebrew"
collate = "hebrew_bin"
}
charset = "$charset"
collate = "$collate"
}
-- 3.sql --
CREATE TABLE `users` (
`name` varchar(255) CHARACTER SET hebrew COLLATE hebrew_bin NOT NULL
)
-- 4.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "name" {
type = varchar(255)
charset = "hebrew"
}
charset = "$charset"
collate = "$collate"
}
-- 5.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "name" {
type = varchar(255)
}
charset = "$charset"
collate = "$collate"
}
-- 5.sql --
CREATE TABLE `users` (
`name` varchar(255) NOT NULL
)
================================================
FILE: internal/integration/testdata/mysql/column-default-expr.txtar
================================================
# Run tests only on MySQL 8.
only mysql8
# Apply schema "1.hcl" on fresh database.
apply 1.hcl
# Compare the result of "SHOW TABLE users" with the content of a file named '1.sql'.
cmpshow users 1.sql
cmphcl 1.hcl
-- 1.hcl --
table "users" {
schema = schema.script_column_default_expr
column "a" {
null = false
type = varchar(255)
default = ""
}
column "b" {
null = false
type = varchar(255)
default = sql("(concat(_utf8mb4'a',`a`,_utf8mb4'\\'s',_utf8mb4'b'))")
}
column "c" {
null = false
type = varchar(255)
default = "a'b"
}
column "d" {
null = false
type = varchar(255)
default = sql("(_utf8mb4'a\\'b')")
}
column "e" {
null = false
type = timestamp
default = "2000-01-01 00:00:00"
}
}
schema "script_column_default_expr" {
charset = "utf8mb4"
collate = "utf8mb4_0900_ai_ci"
}
-- 1.sql --
CREATE TABLE `users` (
`a` varchar(255) NOT NULL DEFAULT '',
`b` varchar(255) NOT NULL DEFAULT (concat(_utf8mb4'a',`a`,_utf8mb4'\'s',_utf8mb4'b')),
`c` varchar(255) NOT NULL DEFAULT 'a''b',
`d` varchar(255) NOT NULL DEFAULT (_utf8mb4'a\'b'),
`e` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00'
)
================================================
FILE: internal/integration/testdata/mysql/column-generated-inspect.txtar
================================================
# Skip MySQL 5.6 as it does not support generated columns.
! only mysql56
apply 1.hcl
cmphcl 1.inspect.hcl
-- 1.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "a" {
type = bool
null = true
}
column "b" {
type = bool
null = true
as = "a"
}
column "c" {
type = bool
null = true
as {
type = STORED
expr = "b"
}
}
column "d e" {
null = false
type = varchar(255)
}
column "d $" {
null = false
type = varchar(255)
}
index "idx_1" {
columns = [column["d e"]]
}
index "idx_2" {
columns = [column["d $"]]
}
}
-- 1.inspect.hcl --
table "users" {
schema = schema.$db
column "a" {
null = true
type = bool
}
column "b" {
null = true
type = bool
as {
expr = "`a`"
type = VIRTUAL
}
}
column "c" {
null = true
type = bool
as {
expr = "`b`"
type = STORED
}
}
column "d e" {
null = false
type = varchar(255)
}
column "d $" {
null = false
type = varchar(255)
}
index "idx_1" {
columns = [column["d e"]]
}
index "idx_2" {
columns = [column["d $"]]
}
}
schema "$db" {
charset = "$charset"
collate = "$collate"
}
================================================
FILE: internal/integration/testdata/mysql/column-generated.txtar
================================================
# Skip MySQL 5.6 as it does not support generated columns.
! only mysql56
apply 1.hcl
cmpshow users 1.sql
! apply 2.fail1.hcl 'changing VIRTUAL generated column "b" to non-generated column is not supported (drop and add is required)'
! apply 2.fail2.hcl 'changing column "a" to VIRTUAL generated column is not supported (drop and add is required)'
! apply 2.fail3.hcl 'changing the store type of generated column "c" from "STORED" to "VIRTUAL" is not supported'
apply 3.hcl
cmpshow users 3.sql
-- 1.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "a" {
type = int
}
column "b" {
type = int
as = "a * 2"
}
column "c" {
type = int
as {
expr = "a * b"
type = STORED
}
}
}
-- 1.sql --
CREATE TABLE `users` (
`a` int(11) NOT NULL,
`b` int(11) GENERATED ALWAYS AS (`a` * 2) VIRTUAL,
`c` int(11) GENERATED ALWAYS AS (`a` * `b`) STORED
)
-- mysql57/1.sql --
CREATE TABLE `users` (
`a` int(11) NOT NULL,
`b` int(11) GENERATED ALWAYS AS ((`a` * 2)) VIRTUAL NOT NULL,
`c` int(11) GENERATED ALWAYS AS ((`a` * `b`)) STORED NOT NULL
)
-- mysql8/1.sql --
CREATE TABLE `users` (
`a` int NOT NULL,
`b` int GENERATED ALWAYS AS ((`a` * 2)) VIRTUAL NOT NULL,
`c` int GENERATED ALWAYS AS ((`a` * `b`)) STORED NOT NULL
)
-- 2.fail1.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "a" {
type = int
}
column "b" {
type = int
}
column "c" {
type = int
as {
expr = "a * b"
type = STORED
}
}
}
-- 2.fail2.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "a" {
type = int
as = "1"
}
column "b" {
type = int
as = "a * 2"
}
column "c" {
type = int
as {
expr = "a * b"
type = VIRTUAL
}
}
}
-- 2.fail3.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "a" {
type = int
}
column "b" {
type = int
as = "a * 2"
}
column "c" {
type = int
as {
expr = "a * b"
type = VIRTUAL
}
}
}
-- 3.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "a" {
type = int
as {
expr = "1"
type = STORED
}
}
column "b" {
type = int
as = "a * 3"
}
column "c" {
type = int
as {
expr = "a * b"
type = STORED
}
}
}
-- 3.sql --
CREATE TABLE `users` (
`a` int(11) GENERATED ALWAYS AS (1) STORED,
`b` int(11) GENERATED ALWAYS AS (`a` * 3) VIRTUAL,
`c` int(11) GENERATED ALWAYS AS (`a` * `b`) STORED
)
-- mysql57/3.sql --
CREATE TABLE `users` (
`a` int(11) GENERATED ALWAYS AS (1) STORED NOT NULL,
`b` int(11) GENERATED ALWAYS AS ((`a` * 3)) VIRTUAL NOT NULL,
`c` int(11) GENERATED ALWAYS AS ((`a` * `b`)) STORED NOT NULL
)
-- mysql8/3.sql --
CREATE TABLE `users` (
`a` int GENERATED ALWAYS AS (1) STORED NOT NULL,
`b` int GENERATED ALWAYS AS ((`a` * 3)) VIRTUAL NOT NULL,
`c` int GENERATED ALWAYS AS ((`a` * `b`)) STORED NOT NULL
)
================================================
FILE: internal/integration/testdata/mysql/column-json.txtar
================================================
only maria*
apply 1.hcl
cmpshow users 1.sql
# The CHECK "json_valid(`name`)" should not be present in the HCL
# description because the "longtext" is converted to "json" type.
cmphcl 1.inspect.hcl
-- 1.hcl --
schema "script_column_json" {}
table "users" {
schema = schema.script_column_json
column "id" {
null = false
type = int
}
column "name" {
null = false
type = json
}
primary_key {
columns = [column.id]
}
}
-- 1.sql --
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`name` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`name`)),
PRIMARY KEY (`id`)
)
-- 1.inspect.hcl --
table "users" {
schema = schema.script_column_json
column "id" {
null = false
type = int
}
column "name" {
null = false
type = json
}
primary_key {
columns = [column.id]
}
}
schema "script_column_json" {
charset = "$charset"
collate = "$collate"
}
================================================
FILE: internal/integration/testdata/mysql/column-time-precision-maria.txtar
================================================
# Each test runs on a clean database.
only maria*
# Apply schema "1.hcl" on fresh database.
apply 1.hcl
# Compare the result of "SHOW TABLE users" with the content of a file named '1.sql'.
cmpshow foo 1.sql
# Files
-- 1.hcl --
schema "$db" {}
table "foo" {
schema = schema.$db
column "id" {
null = false
type = char(36)
}
column "precision_default" {
null = false
type = timestamp
default = sql("CURRENT_TIMESTAMP")
on_update = sql("CURRENT_TIMESTAMP")
}
column "create_time" {
null = false
type = timestamp(6)
default = sql("CURRENT_TIMESTAMP(6)")
}
column "update_time" {
null = false
type = datetime(6)
default = sql("CURRENT_TIMESTAMP(6)")
on_update = sql("CURRENT_TIMESTAMP(6)")
}
primary_key {
columns = [table.foo.column.id, ]
}
}
-- 1.sql --
CREATE TABLE `foo` (
`id` char(36) NOT NULL,
`precision_default` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`create_time` timestamp(6) NOT NULL DEFAULT current_timestamp(6),
`update_time` datetime(6) NOT NULL DEFAULT current_timestamp(6) ON UPDATE current_timestamp(6),
PRIMARY KEY (`id`)
)
================================================
FILE: internal/integration/testdata/mysql/column-time-precision-mysql.txtar
================================================
# Each test runs on a clean database.
only mysql56 mysql57 mysql8
# Apply schema "1.hcl" on fresh database.
apply 1.hcl
# Compare the result of "SHOW TABLE users" with the content of a file named '1.sql'.
cmpshow foo 1.sql
# Files
-- 1.hcl --
schema "$db" {}
table "foo" {
schema = schema.$db
column "id" {
null = false
type = char(36)
}
column "precision_default" {
null = false
type = timestamp
default = sql("CURRENT_TIMESTAMP")
on_update = sql("CURRENT_TIMESTAMP")
}
column "create_time" {
null = false
type = timestamp(6)
default = sql("CURRENT_TIMESTAMP(6)")
}
column "update_time" {
null = false
type = datetime(6)
default = sql("CURRENT_TIMESTAMP(6)")
on_update = sql("CURRENT_TIMESTAMP(6)")
}
primary_key {
columns = [table.foo.column.id, ]
}
}
-- 1.sql --
CREATE TABLE `foo` (
`id` char(36) NOT NULL,
`precision_default` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`create_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
`update_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY (`id`)
)
================================================
FILE: internal/integration/testdata/mysql/foreign-key-add.txtar
================================================
# Each test runs on a clean database.
# Apply schema "1.hcl" on fresh database.
apply 1.hcl
# Check that users exists in the database.
exist users
# The negate version indicates that this command is expected to fail and the
# second argument is an optional pattern for matching on the returned error.
! apply invalid-on-delete-action.hcl 'foreign key constraint was "author_id" SET NULL, but column "author_id" is NOT NULL'
! apply invalid-on-update-action.hcl 'foreign key constraint was "author_id" SET NULL, but column "author_id" is NOT NULL'
apply 2.hcl
exist users posts
cmpshow users posts 2.sql
# Below files represent HCL and SQL. File names defined their index in
# execution order. 1.hcl is executed first, 2.hcl executed second, etc.
-- 1.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
-- invalid-on-delete-action.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
table "posts" {
schema = schema.$db
column "id" {
type = int
}
column "author_id" {
type = int
}
primary_key {
columns = [table.posts.column.id]
}
foreign_key "owner_id" {
columns = [table.posts.column.author_id]
ref_columns = [table.users.column.id]
on_delete = SET_NULL
}
}
-- invalid-on-update-action.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
table "posts" {
schema = schema.$db
column "id" {
type = int
}
column "author_id" {
type = int
}
primary_key {
columns = [table.posts.column.id]
}
foreign_key "owner_id" {
columns = [table.posts.column.author_id]
ref_columns = [table.users.column.id]
on_update = SET_NULL
}
}
-- 2.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
table "posts" {
schema = schema.$db
column "id" {
type = int
}
column "author_id" {
type = int
null = true
}
primary_key {
columns = [table.posts.column.id]
}
foreign_key "owner_id" {
columns = [table.posts.column.author_id]
ref_columns = [table.users.column.id]
on_delete = SET_NULL
}
}
-- 2.sql --
CREATE TABLE `users` (
`id` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `posts` (
`id` int(11) NOT NULL,
`author_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `owner_id` (`author_id`),
CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
)
-- mysql8/2.sql --
CREATE TABLE `users` (
`id` int NOT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `posts` (
`id` int NOT NULL,
`author_id` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `owner_id` (`author_id`),
CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
)
================================================
FILE: internal/integration/testdata/mysql/foreign-key-modify-action.txtar
================================================
# Each test runs on a clean database.
# Apply schema "1.hcl" on fresh database.
apply 1.hcl
cmpshow users posts 1.sql
apply 2.hcl
cmpshow users posts 2.sql
# Below files represent HCL and SQL. File names defined their index in
# execution order. 1.hcl is executed first, 2.hcl executed second, etc.
-- 1.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
table "posts" {
schema = schema.$db
column "id" {
type = int
}
column "author_id" {
type = int
null = true
}
primary_key {
columns = [table.posts.column.id]
}
foreign_key "owner_id" {
columns = [table.posts.column.author_id]
ref_columns = [table.users.column.id]
on_update = SET_NULL
}
}
-- 1.sql --
CREATE TABLE `users` (
`id` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `posts` (
`id` int(11) NOT NULL,
`author_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `owner_id` (`author_id`),
CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON UPDATE SET NULL
)
-- mysql8/1.sql --
CREATE TABLE `users` (
`id` int NOT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `posts` (
`id` int NOT NULL,
`author_id` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `owner_id` (`author_id`),
CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON UPDATE SET NULL
)
-- 2.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
table "posts" {
schema = schema.$db
column "id" {
type = int
}
column "author_id" {
type = int
null = true
}
primary_key {
columns = [table.posts.column.id]
}
foreign_key "owner_id" {
columns = [table.posts.column.author_id]
ref_columns = [table.users.column.id]
on_update = NO_ACTION
on_delete = CASCADE
}
}
-- 2.sql --
CREATE TABLE `users` (
`id` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `posts` (
`id` int(11) NOT NULL,
`author_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `owner_id` (`author_id`),
CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
)
-- mysql8/2.sql --
CREATE TABLE `users` (
`id` int NOT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `posts` (
`id` int NOT NULL,
`author_id` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `owner_id` (`author_id`),
CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
)
================================================
FILE: internal/integration/testdata/mysql/foreign-key.txtar
================================================
only mysql8 maria107
apply 1.hcl
cmpshow t1 t1.sql
cmpshow t2 t2.sql
cmphcl 1.inspect.hcl
-- 1.hcl --
schema "$db" {
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
table "t1" {
schema = schema.$db
column "c1" {
null = false
type = int
}
column "c2" {
null = true
type = int
}
column "c3" {
null = true
type = int
}
primary_key {
columns = [column.c1]
}
index "t1_c2_c3_idx" {
unique = true
columns = [column.c2, column.c3]
}
}
table "t2" {
schema = schema.$db
column "c1" {
null = false
type = int
}
column "c2" {
null = true
type = int
}
column "c3" {
null = true
type = int
}
primary_key {
columns = [column.c1]
}
foreign_key "c2_c3_1" {
columns = [column.c2, column.c3]
ref_columns = [table.t1.column.c2, table.t1.column.c3]
on_update = NO_ACTION
on_delete = NO_ACTION
}
foreign_key "c2_c3_2" {
columns = [column.c2, column.c3]
ref_columns = [table.t1.column.c2, table.t1.column.c3]
on_update = NO_ACTION
on_delete = NO_ACTION
}
}
-- mysql8/t1.sql --
CREATE TABLE `t1` (
`c1` int NOT NULL,
`c2` int DEFAULT NULL,
`c3` int DEFAULT NULL,
PRIMARY KEY (`c1`),
UNIQUE KEY `t1_c2_c3_idx` (`c2`,`c3`)
)
-- mysql8/t2.sql --
CREATE TABLE `t2` (
`c1` int NOT NULL,
`c2` int DEFAULT NULL,
`c3` int DEFAULT NULL,
PRIMARY KEY (`c1`),
KEY `c2_c3_2` (`c2`,`c3`),
CONSTRAINT `c2_c3_1` FOREIGN KEY (`c2`, `c3`) REFERENCES `t1` (`c2`, `c3`),
CONSTRAINT `c2_c3_2` FOREIGN KEY (`c2`, `c3`) REFERENCES `t1` (`c2`, `c3`)
)
-- t1.sql --
CREATE TABLE `t1` (
`c1` int(11) NOT NULL,
`c2` int(11) DEFAULT NULL,
`c3` int(11) DEFAULT NULL,
PRIMARY KEY (`c1`),
UNIQUE KEY `t1_c2_c3_idx` (`c2`,`c3`)
)
-- t2.sql --
CREATE TABLE `t2` (
`c1` int(11) NOT NULL,
`c2` int(11) DEFAULT NULL,
`c3` int(11) DEFAULT NULL,
PRIMARY KEY (`c1`),
KEY `c2_c3_2` (`c2`,`c3`),
CONSTRAINT `c2_c3_1` FOREIGN KEY (`c2`, `c3`) REFERENCES `t1` (`c2`, `c3`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `c2_c3_2` FOREIGN KEY (`c2`, `c3`) REFERENCES `t1` (`c2`, `c3`) ON DELETE NO ACTION ON UPDATE NO ACTION
)
-- 1.inspect.hcl --
table "t1" {
schema = schema.script_foreign_key
column "c1" {
null = false
type = int
}
column "c2" {
null = true
type = int
}
column "c3" {
null = true
type = int
}
primary_key {
columns = [column.c1]
}
index "t1_c2_c3_idx" {
unique = true
columns = [column.c2, column.c3]
}
}
table "t2" {
schema = schema.script_foreign_key
column "c1" {
null = false
type = int
}
column "c2" {
null = true
type = int
}
column "c3" {
null = true
type = int
}
primary_key {
columns = [column.c1]
}
foreign_key "c2_c3_1" {
columns = [column.c2, column.c3]
ref_columns = [table.t1.column.c2, table.t1.column.c3]
on_update = NO_ACTION
on_delete = NO_ACTION
}
foreign_key "c2_c3_2" {
columns = [column.c2, column.c3]
ref_columns = [table.t1.column.c2, table.t1.column.c3]
on_update = NO_ACTION
on_delete = NO_ACTION
}
index "c2_c3_2" {
columns = [column.c2, column.c3]
}
}
schema "script_foreign_key" {
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
================================================
FILE: internal/integration/testdata/mysql/index-add-drop.txtar
================================================
# Each test runs on a clean database.
# Apply schema "1.hcl" on fresh database.
apply 1.hcl
cmpshow users 1.sql
# Add index to table "users".
apply 2.hcl
cmpshow users 2.sql
# Drop uniqueness from index.
apply 3.hcl
cmpshow users 3.sql
# Drop index.
apply 1.hcl
cmpshow users 1.sql
# Below files represent HCL and SQL. File names defined their index in
# execution order. 1.hcl is executed first, 2.hcl executed second, etc.
-- 1.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "rank" {
type = bigint
}
}
-- 1.sql --
CREATE TABLE `users` (
`rank` bigint(20) NOT NULL
)
-- mysql8/1.sql --
CREATE TABLE `users` (
`rank` bigint NOT NULL
)
-- 2.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "rank" {
type = bigint
}
index "rank_idx" {
unique = true
columns = [table.users.column.rank]
}
}
-- 2.sql --
CREATE TABLE `users` (
`rank` bigint(20) NOT NULL,
UNIQUE KEY `rank_idx` (`rank`)
)
-- mysql8/2.sql --
CREATE TABLE `users` (
`rank` bigint NOT NULL,
UNIQUE KEY `rank_idx` (`rank`)
)
-- 3.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "rank" {
type = bigint
}
index "rank_idx" {
columns = [table.users.column.rank]
}
}
-- 3.sql --
CREATE TABLE `users` (
`rank` bigint(20) NOT NULL,
KEY `rank_idx` (`rank`)
)
-- mysql8/3.sql --
CREATE TABLE `users` (
`rank` bigint NOT NULL,
KEY `rank_idx` (`rank`)
)
================================================
FILE: internal/integration/testdata/mysql/index-desc.txtar
================================================
# Each test runs on a clean database.
# Run this test only on MySQL 8 as it is not supported by other versions.
only mysql8
# Apply schema "1.hcl" on fresh database.
apply 1.hcl
cmpshow users 1.sql
# Drop the "DESC" option from the key part.
apply 2.hcl
cmpshow users 2.sql
# Use of "columns" instead of "on" should not trigger a change.
synced 2-no-change.hcl
apply 3.hcl
cmpshow users 3.sql
# Below files represent HCL and SQL. File names defined their index in
# execution order. 1.hcl is executed first, 2.hcl executed second, etc.
-- 1.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "rank" {
type = bigint
}
index "rank_idx" {
on {
desc = true
column = table.users.column.rank
}
}
}
-- 1.sql --
CREATE TABLE `users` (
`rank` bigint NOT NULL,
KEY `rank_idx` (`rank` DESC)
)
-- 2.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "rank" {
type = bigint
}
index "rank_idx" {
on {
column = table.users.column.rank
}
}
}
-- 2.sql --
CREATE TABLE `users` (
`rank` bigint NOT NULL,
KEY `rank_idx` (`rank`)
)
-- 2-no-change.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "rank" {
type = bigint
}
index "rank_idx" {
columns = [
table.users.column.rank,
]
}
}
-- 3.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "rank" {
type = bigint
}
column "score" {
type = int
}
index "rank_score_idx" {
on {
column = table.users.column.rank
}
on {
column = table.users.column.score
desc = true
}
}
}
-- 3.sql --
CREATE TABLE `users` (
`rank` bigint NOT NULL,
`score` int NOT NULL,
KEY `rank_score_idx` (`rank`,`score` DESC)
)
================================================
FILE: internal/integration/testdata/mysql/index-expr.txtar
================================================
# Run this test only on MySQL 8 as it is not supported by other versions.
only mysql8
apply 1.hcl
cmpshow users 1.sql
apply 2.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "first_name" {
null = false
type = varchar(128)
}
column "last_name" {
null = false
type = varchar(128)
}
index "full_name" {
on {
expr = "concat(`first_name`, `last_name`)"
}
}
}
-- 1.sql --
CREATE TABLE `users` (
`first_name` varchar(128) NOT NULL,
`last_name` varchar(128) NOT NULL,
KEY `full_name` ((concat(`first_name`,`last_name`)))
)
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "first_name" {
null = false
type = varchar(128)
}
column "last_name" {
null = false
type = varchar(128)
}
index "full_name" {
on {
expr = "concat(`first_name`, '\\'s first name')"
}
}
}
-- 2.sql --
CREATE TABLE `users` (
`first_name` varchar(128) NOT NULL,
`last_name` varchar(128) NOT NULL,
KEY `full_name` ((concat(`first_name`,_utf8mb4'\'s first name')))
)
================================================
FILE: internal/integration/testdata/mysql/index-prefix.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
# Change prefix.
apply 2.hcl
cmpshow users 2.sql
# Drop prefix.
apply 3.hcl
cmpshow users 3.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
type = varchar(255)
}
index "user_name" {
on {
column = column.name
prefix = 64
}
}
}
-- 1.sql --
CREATE TABLE `users` (
`name` varchar(255) NOT NULL,
KEY `user_name` (`name`(64))
)
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
type = varchar(255)
}
index "user_name" {
on {
column = column.name
prefix = 128
}
}
}
-- 2.sql --
CREATE TABLE `users` (
`name` varchar(255) NOT NULL,
KEY `user_name` (`name`(128))
)
-- 3.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
type = varchar(128)
}
index "user_name" {
on {
column = column.name
}
}
}
-- 3.sql --
CREATE TABLE `users` (
`name` varchar(128) NOT NULL,
KEY `user_name` (`name`)
)
================================================
FILE: internal/integration/testdata/mysql/index-type.txtar
================================================
only mysql8 mysql57
apply 1.hcl
cmpshow users 1.sql
# Drop an index.
apply 2.hcl
cmpshow users 2.sql
atlas schema inspect --url file://schema.v1.sql --dev-url DEV_URL --format '{{ sql . }}'
stdout '-- Create "geom" table'
stdout 'CREATE TABLE `geom` \(`g` geometry NOT NULL, SPATIAL INDEX `idx` \(`g`\)\) .*'
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "text" {
null = false
type = text
}
index "users_text" {
type = FULLTEXT
columns = [column.text]
}
index "ngram_text" {
type = FULLTEXT
parser = ngram
columns = [column.text]
}
}
-- 1.sql --
CREATE TABLE `users` (
`text` text NOT NULL,
FULLTEXT KEY `ngram_text` (`text`) /*!50100 WITH PARSER `ngram` */ ,
FULLTEXT KEY `users_text` (`text`)
)
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "text" {
null = false
type = text
}
}
-- 2.sql --
CREATE TABLE `users` (
`text` text NOT NULL
)
-- schema.v1.sql --
CREATE TABLE geom (g GEOMETRY NOT NULL);
CREATE SPATIAL INDEX idx ON geom (g);
================================================
FILE: internal/integration/testdata/mysql/index-unique.txtar
================================================
apply 1.hcl
cmpshow t 1.sql
# Insert a few records to the table, and cause the new desired change to fail.
execsql 'INSERT INTO $db.t (c, d) VALUES (1, 1), (1, 2), (1, 3)'
! apply 2.fail.hcl "Error 1062: Duplicate entry '1' for key 'c'"
apply 2.hcl
cmpshow t 2.sql
-- 1.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "t" {
schema = schema.$db
column "c" {
type = bigint
}
column "d" {
type = bigint
}
index "c" {
unique = true
columns = [column.c, column.d]
}
}
-- 1.sql --
CREATE TABLE `t` (
`c` bigint(20) NOT NULL,
`d` bigint(20) NOT NULL,
UNIQUE KEY `c` (`c`,`d`)
)
-- mysql8/1.sql --
CREATE TABLE `t` (
`c` bigint NOT NULL,
`d` bigint NOT NULL,
UNIQUE KEY `c` (`c`,`d`)
)
-- 2.fail.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "t" {
schema = schema.$db
column "c" {
type = bigint
}
index "c" {
unique = true
columns = [column.c]
}
}
-- 2.hcl --
schema "$db" {
charset = "$charset"
collate = "$collate"
}
table "t" {
schema = schema.$db
column "c" {
type = bigint
}
index "c" {
columns = [column.c]
}
}
-- 2.sql --
CREATE TABLE `t` (
`c` bigint(20) NOT NULL,
KEY `c` (`c`)
)
-- mysql8/2.sql --
CREATE TABLE `t` (
`c` bigint NOT NULL,
KEY `c` (`c`)
)
================================================
FILE: internal/integration/testdata/mysql/primary-key-parts.txtar
================================================
only mysql8
# Version 1.
atlas schema inspect --url file://schema.v1.sql --dev-url URL > got
cmp got schema.v1.hcl
atlas schema inspect --url file://schema.v1.hcl --dev-url URL > got
cmp got schema.v1.hcl
atlas migrate diff v1 --to file://schema.v1.hcl --dev-url URL
cmpmig 0 migration.v1.sql
atlas migrate diff v1-check --to file://schema.v1.hcl --dev-url URL
stdout 'The migration directory is synced with the desired state, no changes to be made'
# Version 2.
atlas migrate diff v2 --to file://schema.v2.hcl --dev-url URL
cmpmig 1 migration.v2.sql
atlas migrate diff v2-check --to file://schema.v2.hcl --dev-url URL
stdout 'The migration directory is synced with the desired state, no changes to be made'
-- schema.v1.sql --
CREATE TABLE `t1` (`id` tinytext NOT NULL, PRIMARY KEY (`id` (7)));
CREATE TABLE `t2` (`id` tinytext NOT NULL, PRIMARY KEY (`id` (7) DESC));
-- schema.v1.hcl --
table "t1" {
schema = schema.script_primary_key_parts
column "id" {
null = false
type = tinytext
}
primary_key {
on {
column = column.id
prefix = 7
}
}
}
table "t2" {
schema = schema.script_primary_key_parts
column "id" {
null = false
type = tinytext
}
primary_key {
on {
desc = true
column = column.id
prefix = 7
}
}
}
schema "script_primary_key_parts" {
charset = "utf8mb4"
collate = "utf8mb4_0900_ai_ci"
}
-- migration.v1.sql --
-- Create "t1" table
CREATE TABLE `t1` (`id` tinytext NOT NULL, PRIMARY KEY (`id` (7))) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- Create "t2" table
CREATE TABLE `t2` (`id` tinytext NOT NULL, PRIMARY KEY (`id` (7) DESC)) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- schema.v2.hcl --
table "t1" {
schema = schema.script_primary_key_parts
column "id" {
null = false
type = tinytext
}
column "id2" {
null = false
type = tinytext
}
primary_key {
on {
column = column.id
prefix = 7
}
on {
column = column.id2
prefix = 1
}
}
}
table "t2" {
schema = schema.script_primary_key_parts
column "id" {
null = false
type = tinytext
}
primary_key {
on {
desc = false
column = column.id
prefix = 6
}
}
}
schema "script_primary_key_parts" {
charset = "utf8mb4"
collate = "utf8mb4_0900_ai_ci"
}
-- migration.v2.sql --
-- Modify "t1" table
ALTER TABLE `t1` ADD COLUMN `id2` tinytext NOT NULL, DROP PRIMARY KEY, ADD PRIMARY KEY (`id` (7), `id2` (1));
-- Modify "t2" table
ALTER TABLE `t2` DROP PRIMARY KEY, ADD PRIMARY KEY (`id` (6));
================================================
FILE: internal/integration/testdata/mysql/primary-key.txtar
================================================
only mysql8
# Create table.
apply 1.hcl
cmpshow users 1.sql
# Add a primary-key.
apply 2.hcl
cmpshow users 2.sql
# Modify the primary-key column and type.
apply 3.hcl
cmpshow users 3.sql
# Drop the primary-key.
apply 1.hcl
cmpshow users 1.sql
-- 1.hcl --
schema "$db" {
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
table "users" {
schema = schema.$db
column "id" {
null = false
type = varchar(128)
}
column "oid" {
null = false
type = varchar(128)
}
}
-- 1.sql --
CREATE TABLE `users` (
`id` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,
`oid` varchar(128) COLLATE utf8mb4_general_ci NOT NULL
)
-- 2.hcl --
schema "$db" {
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
table "users" {
schema = schema.$db
column "id" {
null = false
type = varchar(128)
}
column "oid" {
null = false
type = varchar(128)
}
primary_key {
columns = [column.id]
}
}
-- 2.sql --
CREATE TABLE `users` (
`id` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,
`oid` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`id`)
)
-- 3.hcl --
schema "$db" {
charset = "utf8mb4"
collate = "utf8mb4_general_ci"
}
table "users" {
schema = schema.$db
column "id" {
null = false
type = varchar(128)
}
column "oid" {
null = false
type = varchar(128)
}
primary_key {
columns = [column.oid]
type = HASH
}
}
-- 3.sql --
CREATE TABLE `users` (
`id` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,
`oid` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`oid`)
)
================================================
FILE: internal/integration/testdata/mysql/table-engine.txtar
================================================
only mysql8
# InnoDB as the default storage engine.
apply 1.hcl
cmphcl 1.inspect.hcl
# Change the InnoDB (default storage engine) to MyISAM.
apply 2.hcl
cmphcl 2.inspect.hcl
# Drop MyISAM changes the engine to the default (InnoDB).
apply 3.hcl
cmphcl 3.inspect.hcl
-- 1.hcl --
schema "script_table_engine" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
engine = InnoDB
column "name" {
null = false
type = varchar(255)
}
charset = "$charset"
collate = "$collate"
}
-- 1.inspect.hcl --
table "users" {
schema = schema.script_table_engine
column "name" {
null = false
type = varchar(255)
}
}
schema "script_table_engine" {
charset = "utf8mb4"
collate = "utf8mb4_0900_ai_ci"
}
-- 2.hcl --
schema "script_table_engine" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
engine = MyISAM
column "name" {
null = false
type = varchar(255)
}
charset = "$charset"
collate = "$collate"
}
-- 2.inspect.hcl --
table "users" {
schema = schema.script_table_engine
engine = MyISAM
column "name" {
null = false
type = varchar(255)
}
}
schema "script_table_engine" {
charset = "utf8mb4"
collate = "utf8mb4_0900_ai_ci"
}
-- 3.hcl --
schema "script_table_engine" {
charset = "$charset"
collate = "$collate"
}
table "users" {
schema = schema.$db
column "name" {
null = false
type = varchar(255)
}
charset = "$charset"
collate = "$collate"
}
-- 3.inspect.hcl --
table "users" {
schema = schema.script_table_engine
column "name" {
null = false
type = varchar(255)
}
}
schema "script_table_engine" {
charset = "utf8mb4"
collate = "utf8mb4_0900_ai_ci"
}
================================================
FILE: internal/integration/testdata/postgres/cli-inspect-file.txtar
================================================
# inspect without dev-db will failed
! atlas schema inspect -u file://a.sql
stderr 'Error: --dev-url cannot be empty'
# inspect file to HCL
atlas schema inspect -u file://a.sql --dev-url URL > inspected.hcl
cmp inspected.hcl script_cli_inspect.hcl
# inspect file to SQL
atlas schema inspect -u file://a.sql --dev-url URL --format '{{ sql . }}' > inspected.sql
cmp inspected.sql script_cli_inspect.sql
-- a.sql --
create table users (
id int NOT NULL,
PRIMARY KEY (id)
)
-- script_cli_inspect.hcl --
table "users" {
schema = schema.script_cli_inspect_file
column "id" {
null = false
type = integer
}
primary_key {
columns = [column.id]
}
}
schema "script_cli_inspect_file" {
}
-- script_cli_inspect.sql --
-- Create "users" table
CREATE TABLE "users" ("id" integer NOT NULL, PRIMARY KEY ("id"));
================================================
FILE: internal/integration/testdata/postgres/cli-inspect.txtar
================================================
apply 1.hcl
# test url flag
atlas schema inspect -u URL > inspected.hcl
cmp inspected.hcl script_cli_inspect.hcl
# test exclude flag on table.
atlas schema inspect -u URL --exclude "users" > inspected.hcl
cmp inspected.hcl notable.hcl
# test exclude flag on column.
atlas schema inspect -u URL --exclude "*.[ab]*" > inspected.hcl
cmp inspected.hcl id.hcl
# test exclude flag on column.
atlas schema inspect -u URL --exclude "*.*" > inspected.hcl
cmp inspected.hcl nocolumn.hcl
-- 1.hcl --
table "users" {
schema = schema.$db
column "id" {
null = false
type = int
}
column "a" {
null = false
type = int
}
column "b" {
null = false
type = int
}
column "ab" {
null = false
type = int
}
column "ac" {
null = false
type = int4
}
}
schema "$db" {
}
-- script_cli_inspect.hcl --
table "users" {
schema = schema.script_cli_inspect
column "id" {
null = false
type = integer
}
column "a" {
null = false
type = integer
}
column "b" {
null = false
type = integer
}
column "ab" {
null = false
type = integer
}
column "ac" {
null = false
type = integer
}
}
schema "script_cli_inspect" {
}
-- empty.hcl --
-- notable.hcl --
schema "script_cli_inspect" {
}
-- id.hcl --
table "users" {
schema = schema.script_cli_inspect
column "id" {
null = false
type = integer
}
}
schema "script_cli_inspect" {
}
-- nocolumn.hcl --
table "users" {
schema = schema.script_cli_inspect
}
schema "script_cli_inspect" {
}
================================================
FILE: internal/integration/testdata/postgres/cli-migrate-apply-datasrc.txtar
================================================
only postgres14
atlas migrate hash
atlas migrate apply --url URL --env dev --var "url=URL" --var "pattern=script_cli_migrate_apply_datasrc"
stdout 'Migrating to version 1 \(1 migrations in total\):'
-- atlas.hcl --
variable "url" {
type = string
}
variable "pattern" {
type = string
}
data "sql" "tenants" {
url = var.url
query = < CREATE TABLE "users" \("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "age" bigint NOT NULL, "name" character varying NOT NULL, PRIMARY KEY \("id"\)\);'
stdout '-- migrating version 2'
stdout '-> CREATE UNIQUE INDEX "users_age_key" ON "users" \("age"\);'
stdout '-- migrating version 3'
stdout '-> CREATE TABLE "pets" \("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" character varying NOT NULL, PRIMARY KEY \("id"\)\);'
stdout '-- 3 migrations'
stdout '-- 3 sql statements'
cmpshow users users.sql
cmpshow pets pets.sql
atlas migrate apply --url URL --revisions-schema $db 1
stdout 'No migration files to execute'
clearSchema
# Apply one by one
atlas migrate apply --url URL --revisions-schema $db 1
stdout 'Migrating to version 1 \(1 migrations in total\):'
cmpshow users users_1.sql
atlas migrate apply --url URL --revisions-schema $db 1
stdout 'Migrating to version 2 from 1 \(1 migrations in total\):'
cmpshow users users.sql
atlas migrate apply --url URL --revisions-schema $db 1
stdout 'Migrating to version 3 from 2 \(1 migrations in total\):'
cmpshow users users.sql
cmpshow pets pets.sql
atlas migrate apply --url URL --revisions-schema $db 1
stdout 'No migration files to execute'
clearSchema
# Move the broken migration into the migrations directory and check the different transaction modes.
cp broken.sql migrations/4_fourth.sql
atlas migrate hash
! atlas migrate apply --url URL --revisions-schema $db --tx-mode invalid
stderr 'unknown tx-mode "invalid"'
# Test --tx-mode all
! atlas migrate apply --url URL --revisions-schema $db --tx-mode all
stderr 'executing statement "THIS IS A FAILING STATEMENT;" from version "4"'
atlas schema inspect --url URL --exclude atlas_schema_revisions
cmp stdout empty.hcl
# Apply one migration, after rolling everything back, the first revision must still exist.
atlas migrate apply --url URL --revisions-schema $db 1
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users
cmp stdout empty.hcl
cmpshow users users_1.sql
! atlas migrate apply --url URL --revisions-schema $db --tx-mode all
stderr 'executing statement "THIS IS A FAILING STATEMENT;" from version "4"'
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users
cmp stdout empty.hcl
# If the broken migration is gone, we can apply everything without any problems.
rm migrations/4_fourth.sql
atlas migrate hash
atlas migrate apply --url URL --revisions-schema $db
cmpshow users users.sql
cmpshow pets pets.sql
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets
cmp stdout empty.hcl
clearSchema
# Test --tx-mode file
cp broken.sql migrations/4_fourth.sql
atlas migrate hash
! atlas migrate apply --url URL --revisions-schema $db --tx-mode file
stderr 'executing statement "THIS IS A FAILING STATEMENT;" from version "4"'
atlas schema inspect --url URL --exclude atlas_schema_revisions
cmpshow users users.sql
cmpshow pets pets.sql
# Table "broken" does not exist since we rolled back that migration.
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets
cmp stdout empty.hcl
# If the broken migration is gone, we can apply everything without any problems.
rm migrations/4_fourth.sql
atlas migrate hash
atlas migrate apply --url URL --revisions-schema $db
cmpshow users users.sql
cmpshow pets pets.sql
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets
cmp stdout empty.hcl
clearSchema
# Test --tx-mode none
cp broken.sql migrations/4_fourth.sql
atlas migrate hash
! atlas migrate apply --url URL --revisions-schema $db --tx-mode none
stderr 'executing statement "THIS IS A FAILING STATEMENT;" from version "4"'
atlas schema inspect --url URL --exclude atlas_schema_revisions
cmpshow users users.sql
cmpshow pets pets.sql
# Table "broken" does exist since we do not have transactions.
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets
cmp stdout broken.hcl
-- migrations/1_first.sql --
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "age" bigint NOT NULL, "name" character varying NOT NULL, PRIMARY KEY ("id"));
-- migrations/2_second.sql --
CREATE UNIQUE INDEX "users_age_key" ON "users" ("age");
-- migrations/3_third.sql --
CREATE TABLE "pets" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" character varying NOT NULL, PRIMARY KEY ("id"));
-- broken.sql --
CREATE TABLE "broken" ("id" bigint);
THIS IS A FAILING STATEMENT;
-- empty.hcl --
schema "script_cli_migrate_apply" {
}
-- broken.hcl --
table "broken" {
schema = schema.script_cli_migrate_apply
column "id" {
null = true
type = bigint
}
}
schema "script_cli_migrate_apply" {
}
-- users.sql --
Table "script_cli_migrate_apply.users"
Column | Type | Collation | Nullable | Default
--------+-------------------+-----------+----------+----------------------------------
id | bigint | | not null | generated by default as identity
age | bigint | | not null |
name | character varying | | not null |
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
"users_age_key" UNIQUE, btree (age)
-- users_1.sql --
Table "script_cli_migrate_apply.users"
Column | Type | Collation | Nullable | Default
--------+-------------------+-----------+----------+----------------------------------
id | bigint | | not null | generated by default as identity
age | bigint | | not null |
name | character varying | | not null |
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
-- pets.sql --
Table "script_cli_migrate_apply.pets"
Column | Type | Collation | Nullable | Default
--------+-------------------+-----------+----------+----------------------------------
id | bigint | | not null | generated by default as identity
name | character varying | | not null |
Indexes:
"pets_pkey" PRIMARY KEY, btree (id)
================================================
FILE: internal/integration/testdata/postgres/cli-migrate-diff-unsupported.txtar
================================================
atlas migrate hash
atlas migrate diff --dev-url URL --to file://./schema.hcl
cmpmig 1 2.expected.sql
# Test no diff.
atlas migrate diff --dev-url URL --to file://./schema.hcl
stdout 'The migration directory is synced with the desired state, no changes to be made'
-- migrations/1_baseline.sql --
CREATE OR REPLACE FUNCTION random_id(n INTEGER) RETURNS TEXT AS $$
DECLARE
chars TEXT := '0123456789';
result TEXT := '';
i INTEGER := 0;
BEGIN
FOR i IN 1..n LOOP
result := result || substr(chars, trunc(random()*10)::integer + 1, 1);
END LOOP;
RETURN result;
END;
$$ LANGUAGE plpgsql;
-- schema.hcl --
schema "script_cli_migrate_diff_unsupported" {}
table "users" {
schema = schema.script_cli_migrate_diff_unsupported
column "id" {
null = false
type = text
default = sql("random_id(10)")
}
}
-- 2.expected.sql --
-- Create "users" table
CREATE TABLE "users" ("id" text NOT NULL DEFAULT random_id(10));
================================================
FILE: internal/integration/testdata/postgres/cli-migrate-diff.txtar
================================================
exec mkdir migrations
! atlas migrate diff --to file://1.hcl --dir file://migrations
stderr '"dev-url" not set'
! atlas migrate diff --dev-url postgres://devdb --dir file://migrations
stderr '"to" not set'
atlas migrate diff --dev-url URL --to file://./1.hcl first
cmpmig 0 1.sql
atlas migrate diff --dev-url URL --to file://./2.hcl second
cmpmig 1 2.sql
-- 1.hcl --
schema "script_cli_migrate_diff" {}
table "users" {
schema = schema.script_cli_migrate_diff
column "id" {
null = false
type = bigint
}
primary_key {
columns = [column.id]
}
}
-- 1.sql --
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL, PRIMARY KEY ("id"));
-- 2.hcl --
schema "script_cli_migrate_diff" {}
table "users" {
schema = schema.script_cli_migrate_diff
column "id" {
null = false
type = bigint
}
column "create_time" {
null = false
type = timestamp(4)
default = sql("CURRENT_TIMESTAMP(4)")
}
primary_key {
columns = [column.id]
}
}
-- 2.sql --
-- Modify "users" table
ALTER TABLE "users" ADD COLUMN "create_time" timestamp(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4);
================================================
FILE: internal/integration/testdata/postgres/cli-migrate-status.txtar
================================================
# make sure sum file is correct
atlas migrate hash
# for clean database
atlas migrate status --url URL --revisions-schema $db
cmp stdout status_clean.txt
# apply one
atlas migrate apply --url URL --revisions-schema $db 1
atlas migrate status --url URL --revisions-schema $db
cmp stdout status_one_applied.txt
# apply next (and last)
atlas migrate apply --url URL --revisions-schema $db 1
atlas migrate status --url URL --revisions-schema $db
cmp stdout status_ok.txt
-- migrations/1.sql --
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED ALWAYS AS IDENTITY, PRIMARY KEY ("id"));
-- migrations/2.sql --
ALTER TABLE "users" ADD COLUMN "happy" boolean NOT NULL DEFAULT true;
-- broken_migration.sql --
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED ALWAYS AS IDENTITY, PRIMARY KEY ("id"));
THIS LINE ADDS A SYNTAX ERROR;
-- fixed_migration.sql --
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED ALWAYS AS IDENTITY, PRIMARY KEY ("id"));
ALTER TABLE "users" ADD COLUMN "happy" boolean NOT NULL DEFAULT true;
-- status_clean.txt --
Migration Status: PENDING
-- Current Version: No migration applied yet
-- Next Version: 1
-- Executed Files: 0
-- Pending Files: 2
-- status_one_applied.txt --
Migration Status: PENDING
-- Current Version: 1
-- Next Version: 2
-- Executed Files: 1
-- Pending Files: 1
-- status_ok.txt --
Migration Status: OK
-- Current Version: 2
-- Next Version: Already at latest version
-- Executed Files: 2
-- Pending Files: 0
================================================
FILE: internal/integration/testdata/postgres/column-array.txtar
================================================
apply 1.hcl
cmpshow logs 1.sql
# Change size of the underlying type.
apply 2.change-size.hcl
cmpshow logs 2.sql
synced 3.nochange.hcl
synced 4.nochange.hcl
apply 5.hcl
cmpshow logs 5.sql
-- 1.hcl --
schema "$db" {}
table "logs" {
schema = schema.$db
column "records" {
null = false
type = sql("varchar(255)[]")
}
}
-- 1.sql --
Table "script_column_array.logs"
Column | Type | Collation | Nullable | Default
---------+--------------------------+-----------+----------+---------
records | character varying(255)[] | | not null |
-- 2.change-size.hcl --
schema "$db" {}
table "logs" {
schema = schema.$db
column "records" {
null = false
type = sql("varchar(100) ARRAY")
}
}
-- 2.sql --
Table "script_column_array.logs"
Column | Type | Collation | Nullable | Default
---------+--------------------------+-----------+----------+---------
records | character varying(100)[] | | not null |
-- 3.nochange.hcl --
schema "$db" {}
table "logs" {
schema = schema.$db
column "records" {
null = false
type = sql("varchar(100) ARRAY")
}
}
-- 4.nochange.hcl --
schema "$db" {}
table "logs" {
schema = schema.$db
column "records" {
null = false
type = sql("varchar(100) [10][]")
}
}
-- 5.hcl --
schema "$db" {}
table "logs" {
schema = schema.$db
column "a" {
null = false
type = sql("int[1]")
}
column "b" {
null = false
type = sql("int ARRAY[1]")
}
column "c" {
null = false
type = sql("character varying(100) ARRAY[1]")
}
column "d" {
null = false
type = sql("point [][1]")
}
}
-- 5.sql --
Table "script_column_array.logs"
Column | Type | Collation | Nullable | Default
--------+--------------------------+-----------+----------+---------
a | integer[] | | not null |
b | integer[] | | not null |
c | character varying(100)[] | | not null |
d | point[] | | not null |
================================================
FILE: internal/integration/testdata/postgres/column-bit.txtar
================================================
apply 1.hcl
cmpshow t 1.sql
# Change size of the underlying type.
apply 2.hcl
cmpshow t 2.sql
-- 1.hcl --
schema "$db" {}
table "t" {
schema = schema.$db
column "c1" {
// Equals to bit(1).
type = bit
}
column "c2" {
type = bit(2)
}
column "c3" {
// Unlimited length.
type = bit_varying
}
column "c4" {
type = bit_varying(1)
}
}
-- 1.sql --
Table "script_column_bit.t"
Column | Type | Collation | Nullable | Default
--------+----------------+-----------+----------+---------
c1 | bit(1) | | not null |
c2 | bit(2) | | not null |
c3 | bit varying | | not null |
c4 | bit varying(1) | | not null |
-- 2.hcl --
schema "$db" {}
table "t" {
schema = schema.$db
column "c1" {
// No change.
type = bit(1)
}
column "c2" {
// Reduce size.
type = bit(1)
}
column "c3" {
// Add size.
type = bit_varying(4)
}
column "c4" {
// Increase size.
type = bit_varying(64)
}
}
-- 2.sql --
Table "script_column_bit.t"
Column | Type | Collation | Nullable | Default
--------+-----------------+-----------+----------+---------
c1 | bit(1) | | not null |
c2 | bit(1) | | not null |
c3 | bit varying(4) | | not null |
c4 | bit varying(64) | | not null |
================================================
FILE: internal/integration/testdata/postgres/column-comment.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
apply 2.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "created_at" {
null = false
type = timestamp
comment = "without time zone"
}
}
-- 1.sql --
Table "script_column_comment.users"
Column | Type | Collation | Nullable | Default
------------+-----------------------------+-----------+----------+---------
created_at | timestamp without time zone | | not null |
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "created_at" {
null = false
type = timestamptz
comment = "with time zone"
}
}
-- 2.sql --
Table "script_column_comment.users"
Column | Type | Collation | Nullable | Default
------------+--------------------------+-----------+----------+---------
created_at | timestamp with time zone | | not null |
================================================
FILE: internal/integration/testdata/postgres/column-default.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
atlas schema inspect -u URL > got
cmp 1.inspected.hcl got
# Change column default.
apply 2.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
type = character_varying
default = "unknown"
}
column "age" {
type = int
default = 1
}
column "active" {
type = boolean
default = true
}
column "bpchar" {
type = bpchar
default = "foo"
}
}
-- 1.inspected.hcl --
table "users" {
schema = schema.script_column_default
column "name" {
null = false
type = character_varying
default = "unknown"
}
column "age" {
null = false
type = integer
default = 1
}
column "active" {
null = false
type = boolean
default = true
}
column "bpchar" {
null = false
type = bpchar
default = "foo"
}
}
schema "script_column_default" {
}
-- 1.sql --
Table "script_column_default.users"
Column | Type | Collation | Nullable | Default
--------+-------------------+-----------+----------+------------------------------
name | character varying | | not null | 'unknown'::character varying
age | integer | | not null | 1
active | boolean | | not null | true
bpchar | bpchar | | not null | 'foo'::bpchar
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
type = character_varying
default = "anonymous"
}
column "age" {
type = int
default = 0
}
column "active" {
type = boolean
default = false
}
}
-- 2.sql --
Table "script_column_default.users"
Column | Type | Collation | Nullable | Default
--------+-------------------+-----------+----------+--------------------------------
name | character varying | | not null | 'anonymous'::character varying
age | integer | | not null | 0
active | boolean | | not null | false
================================================
FILE: internal/integration/testdata/postgres/column-domain.txtar
================================================
execsql 'CREATE DOMAIN script_column_domain.positive_int AS bigint CHECK (VALUE > 0)'
apply 1.hcl
cmpshow users 1.sql
cmphcl 1.inspect.hcl
-- 1.hcl --
schema "script_column_domain" {}
table "users" {
schema = schema.script_column_domain
column "c1" {
type = sql("script_column_domain.positive_int")
}
}
-- 1.sql --
Table "script_column_domain.users"
Column | Type | Collation | Nullable | Default
--------+-----------------------------------+-----------+----------+---------
c1 | script_column_domain.positive_int | | not null |
-- 1.inspect.hcl --
table "users" {
schema = schema.script_column_domain
column "c1" {
null = false
type = sql("positive_int")
}
}
schema "script_column_domain" {
}
================================================
FILE: internal/integration/testdata/postgres/column-enum-array.txtar
================================================
# Create table with an enum array column.
apply 1.hcl
cmpshow enums 1.sql
# Drop an enum array column.
apply 2.hcl
cmpshow enums 2.sql
# Append an enum array column to an existing table.
apply 3.hcl
cmpshow enums 3.sql
# Append an enum column to existing enum.
apply 4.hcl
cmpshow enums 4.sql
# Append an enum value.
apply 5.hcl
cmphcl 5.inspect.hcl
-- 1.hcl --
schema "$db" {}
enum "status" {
schema = schema.$db
values = ["active", "inactive"]
}
table "enums" {
schema = schema.$db
column "statuses" {
type = sql("status[]")
}
}
-- 1.sql --
Table "script_column_enum_array.enums"
Column | Type | Collation | Nullable | Default
----------+-----------------------------------+-----------+----------+---------
statuses | script_column_enum_array.status[] | | not null |
-- 2.hcl --
schema "$db" {}
table "enums" {
schema = schema.$db
column "a" {
type = int
}
}
-- 2.sql --
Table "script_column_enum_array.enums"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | not null |
-- 3.hcl --
schema "$db" {}
enum "status" {
schema = schema.$db
values = ["active", "inactive"]
}
table "enums" {
schema = schema.$db
column "a" {
type = int
}
column "statuses" {
type = sql("status[]")
}
}
-- 3.sql --
Table "script_column_enum_array.enums"
Column | Type | Collation | Nullable | Default
----------+-----------------------------------+-----------+----------+---------
a | integer | | not null |
statuses | script_column_enum_array.status[] | | not null |
-- 4.hcl --
schema "$db" {}
enum "status" {
schema = schema.$db
values = ["active", "inactive"]
}
table "enums" {
schema = schema.$db
column "a" {
type = int
}
column "statuses" {
type = sql("status[]")
}
column "status" {
type = enum.status
}
}
-- 4.sql --
Table "script_column_enum_array.enums"
Column | Type | Collation | Nullable | Default
----------+-----------------------------------+-----------+----------+---------
a | integer | | not null |
statuses | script_column_enum_array.status[] | | not null |
status | script_column_enum_array.status | | not null |
-- 5.hcl --
schema "$db" {}
enum "status" {
schema = schema.$db
values = ["active", "inactive", "unknown"]
}
table "enums" {
schema = schema.$db
column "a" {
type = int
}
column "statuses" {
type = sql("status[]")
}
column "status" {
type = enum.status
}
}
-- 5.inspect.hcl --
table "enums" {
schema = schema.script_column_enum_array
column "a" {
null = false
type = integer
}
column "statuses" {
null = false
type = sql("status[]")
}
column "status" {
null = false
type = enum.status
}
}
enum "status" {
schema = schema.script_column_enum_array
values = ["active", "inactive", "unknown"]
}
schema "script_column_enum_array" {
}
================================================
FILE: internal/integration/testdata/postgres/column-enum.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
apply 2.hcl
cmpshow users 2.sql
# Drop the enum.
apply 3.hcl
cmpshow users 3.sql
# Add it back.
apply 2.hcl
cmpshow users 2.sql
# Test schema output.
atlas schema inspect -u URL --format '{{ sql . " " }}' > got.sql
cmp got.sql want.sql
# Rename the column.
apply 4.hcl
cmpshow users 4.sql
-- 1.hcl --
schema "$db" {}
enum "status" {
schema = schema.$db
values = ["active", "inactive"]
}
table "users" {
schema = schema.$db
column "type" {
type = enum.status
default = "active"
}
}
-- 1.sql --
Table "script_column_enum.users"
Column | Type | Collation | Nullable | Default
--------+---------------------------+-----------+----------+-------------------------------------
type | script_column_enum.status | | not null | 'active'::script_column_enum.status
-- 2.hcl --
schema "$db" {}
enum "status" {
schema = schema.$db
values = ["active", "inactive"]
}
table "users" {
schema = schema.$db
column "type" {
type = enum.status
default = "inactive"
}
}
-- 2.sql --
Table "script_column_enum.users"
Column | Type | Collation | Nullable | Default
--------+---------------------------+-----------+----------+---------------------------------------
type | script_column_enum.status | | not null | 'inactive'::script_column_enum.status
-- 3.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "int" {
type = int
default = 1
}
}
-- 3.sql --
Table "script_column_enum.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
int | integer | | not null | 1
-- want.sql --
-- Create enum type "status"
CREATE TYPE "status" AS ENUM ('active', 'inactive');
-- Create "users" table
CREATE TABLE "users" (
"type" "status" NOT NULL DEFAULT 'inactive'
);
-- 4.hcl --
schema "$db" {}
enum "status" {
schema = schema.$db
values = ["active", "inactive"]
}
table "users" {
schema = schema.$db
column "renamed" {
type = enum.status
default = "inactive"
}
}
-- 4.sql --
Table "script_column_enum.users"
Column | Type | Collation | Nullable | Default
---------+---------------------------+-----------+----------+---------------------------------------
renamed | script_column_enum.status | | not null | 'inactive'::script_column_enum.status
================================================
FILE: internal/integration/testdata/postgres/column-float.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
apply 2.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "c1" {
type = real
}
column "c2" {
type = double_precision
}
column "c3" {
// Equals to real when precision is between 1 and 24.
type = float(10)
}
column "c4" {
// Equals to double_precision when precision is between 1 and 24.
type = float(30)
}
}
-- 1.sql --
Table "script_column_float.users"
Column | Type | Collation | Nullable | Default
--------+------------------+-----------+----------+---------
c1 | real | | not null |
c2 | double precision | | not null |
c3 | real | | not null |
c4 | double precision | | not null |
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "c1" {
type = double_precision
}
column "c2" {
type = real
}
column "c3" {
type = float(30)
}
column "c4" {
type = float(10)
}
}
-- 2.sql --
Table "script_column_float.users"
Column | Type | Collation | Nullable | Default
--------+------------------+-----------+----------+---------
c1 | double precision | | not null |
c2 | real | | not null |
c3 | double precision | | not null |
c4 | real | | not null |
================================================
FILE: internal/integration/testdata/postgres/column-generated-inspect.txtar
================================================
# Skip PostgreSQL 10, 11 as they do not support generated columns.
! only postgres10|postgres11
apply 1.hcl
cmphcl 1.inspect.hcl
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "a" {
type = int
}
column "b" {
type = int
as = "1"
}
column "c" {
type = int
as {
expr = "2"
type = STORED
}
}
}
-- 1.inspect.hcl --
table "users" {
schema = schema.$db
column "a" {
null = false
type = integer
}
column "b" {
null = false
type = integer
as {
expr = "1"
type = STORED
}
}
column "c" {
null = false
type = integer
as {
expr = "2"
type = STORED
}
}
}
schema "$db" {
}
================================================
FILE: internal/integration/testdata/postgres/column-identity.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
# Change identity generation.
apply 2.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
null = false
type = int
identity {
generated = ALWAYS
start = 10
increment = 10
}
}
}
-- 1.sql --
Table "script_column_identity.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+------------------------------
name | integer | | not null | generated always as identity
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
null = false
type = int
identity {
generated = BY_DEFAULT
start = 10
increment = 10
}
}
}
-- 2.sql --
Table "script_column_identity.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+----------------------------------
name | integer | | not null | generated by default as identity
================================================
FILE: internal/integration/testdata/postgres/column-interval.txtar
================================================
apply 1.hcl
cmpshow logs 1.sql
cmphcl 1.inspect.hcl
-- 1.hcl --
table "logs" {
schema = schema.script_column_interval
column "a" {
null = false
type = interval
default = "3 hours"
}
column "b" {
null = false
type = interval(1)
}
column "c" {
null = false
type = second
}
column "d" {
null = false
type = second(1)
}
column "e" {
null = true
type = day_to_second(4)
}
}
schema "script_column_interval" {}
-- 1.sql --
Table "script_column_interval.logs"
Column | Type | Collation | Nullable | Default
--------+---------------------------+-----------+----------+----------------------
a | interval | | not null | '03:00:00'::interval
b | interval(1) | | not null |
c | interval second | | not null |
d | interval second(1) | | not null |
e | interval day to second(4) | | |
-- 1.inspect.hcl --
table "logs" {
schema = schema.script_column_interval
column "a" {
null = false
type = interval
default = sql("'03:00:00'::interval")
}
column "b" {
null = false
type = interval(1)
}
column "c" {
null = false
type = second
}
column "d" {
null = false
type = second(1)
}
column "e" {
null = true
type = day_to_second(4)
}
}
schema "script_column_interval" {
}
================================================
FILE: internal/integration/testdata/postgres/column-numeric.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
apply 2.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "a" {
null = false
type = numeric
}
column "b" {
null = false
type = numeric(10)
}
column "c" {
null = false
type = numeric(10,2)
}
column "d" {
null = false
type = decimal
}
column "e" {
null = false
type = decimal(10)
}
column "f" {
null = false
type = decimal(10,2)
}
}
-- 1.sql --
Table "script_column_numeric.users"
Column | Type | Collation | Nullable | Default
--------+---------------+-----------+----------+---------
a | numeric | | not null |
b | numeric(10,0) | | not null |
c | numeric(10,2) | | not null |
d | numeric | | not null |
e | numeric(10,0) | | not null |
f | numeric(10,2) | | not null |
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "a" {
null = false
type = numeric(5)
}
column "b" {
null = false
type = numeric(10,2)
}
column "c" {
null = false
type = numeric
}
column "d" {
null = false
type = decimal(4)
}
column "e" {
null = false
type = decimal
}
column "f" {
null = false
type = decimal(10,3)
}
}
-- 2.sql --
Table "script_column_numeric.users"
Column | Type | Collation | Nullable | Default
--------+---------------+-----------+----------+---------
a | numeric(5,0) | | not null |
b | numeric(10,2) | | not null |
c | numeric | | not null |
d | numeric(4,0) | | not null |
e | numeric | | not null |
f | numeric(10,3) | | not null |
================================================
FILE: internal/integration/testdata/postgres/column-range.txtar
================================================
only postgres14 postgres15
apply 1.hcl
cmpshow t 1.sql
-- 1.hcl --
schema "$db" {}
table "t" {
schema = schema.$db
column "r1" {
type = int4range
}
column "r2" {
type = int8range
}
column "r3" {
type = numrange
}
column "r4" {
type = tsrange
}
column "r5" {
type = tstzrange
}
column "r6" {
type = daterange
}
column "r7" {
type = int4multirange
}
column "r8" {
type = int8multirange
}
column "r9" {
type = nummultirange
}
column "r10" {
type = tsmultirange
}
column "r11" {
type = tstzmultirange
}
column "r12" {
type = datemultirange
}
}
-- 1.sql --
Table "script_column_range.t"
Column | Type | Collation | Nullable | Default
--------+----------------+-----------+----------+---------
r1 | int4range | | not null |
r2 | int8range | | not null |
r3 | numrange | | not null |
r4 | tsrange | | not null |
r5 | tstzrange | | not null |
r6 | daterange | | not null |
r7 | int4multirange | | not null |
r8 | int8multirange | | not null |
r9 | nummultirange | | not null |
r10 | tsmultirange | | not null |
r11 | tstzmultirange | | not null |
r12 | datemultirange | | not null |
================================================
FILE: internal/integration/testdata/postgres/column-serial.txtar
================================================
apply 1.hcl
cmpshow t 1.sql
apply 2.hcl
cmpshow t 2.sql
apply 3.hcl
cmpshow t 3.sql
-- 1.hcl --
schema "$db" {}
table "t" {
schema = schema.$db
column "x" {
type = smallserial
}
column "y" {
type = serial
}
column "z" {
type = bigserial
}
}
-- 1.sql --
Table "script_column_serial.t"
Column | Type | Collation | Nullable | Default
--------+----------+-----------+----------+---------------------------------------------------
x | smallint | | not null | nextval('script_column_serial.t_x_seq'::regclass)
y | integer | | not null | nextval('script_column_serial.t_y_seq'::regclass)
z | bigint | | not null | nextval('script_column_serial.t_z_seq'::regclass)
-- 2.hcl --
schema "$db" {}
table "t" {
schema = schema.$db
column "x" {
# Drop sequence.
type = smallint
}
column "y" {
# Drop sequence and change type.
type = bigint
}
column "z" {
# Change sequence type.
type = serial
}
}
-- 2.sql --
Table "script_column_serial.t"
Column | Type | Collation | Nullable | Default
--------+----------+-----------+----------+---------------------------------------------------
x | smallint | | not null |
y | bigint | | not null |
z | integer | | not null | nextval('script_column_serial.t_z_seq'::regclass)
-- 3.hcl --
schema "$db" {}
table "t" {
schema = schema.$db
column "x" {
# Add sequence.
type = smallserial
}
column "y" {
# Add sequence and change type.
type = serial
}
}
-- 3.sql --
Table "script_column_serial.t"
Column | Type | Collation | Nullable | Default
--------+----------+-----------+----------+---------------------------------------------------
x | smallint | | not null | nextval('script_column_serial.t_x_seq'::regclass)
y | integer | | not null | nextval('script_column_serial.t_y_seq'::regclass)
================================================
FILE: internal/integration/testdata/postgres/column-textsearch.txtar
================================================
apply 1.hcl
cmpshow t 1.sql
cmphcl 1.inspect.hcl
-- 1.hcl --
schema "script_column_textsearch" {}
table "t" {
schema = schema.script_column_textsearch
column "tsv" {
type = tsvector
}
column "tsq" {
type = tsquery
}
index "idx_tsv" {
type = GIN
columns = [column.tsv]
}
}
-- 1.sql --
Table "script_column_textsearch.t"
Column | Type | Collation | Nullable | Default
--------+----------+-----------+----------+---------
tsv | tsvector | | not null |
tsq | tsquery | | not null |
Indexes:
"idx_tsv" gin (tsv)
-- 1.inspect.hcl --
table "t" {
schema = schema.script_column_textsearch
column "tsv" {
null = false
type = tsvector
}
column "tsq" {
null = false
type = tsquery
}
index "idx_tsv" {
columns = [column.tsv]
type = GIN
}
}
schema "script_column_textsearch" {
}
================================================
FILE: internal/integration/testdata/postgres/column-time-precision.txtar
================================================
# Apply schema "1.hcl" on fresh database.
apply 1.hcl
# Compare the result of "\d tbl" with the content of a file named '1.sql'.
cmpshow tbl 1.sql
apply 2.hcl
cmpshow tbl 2.sql
# Files
-- 1.hcl --
schema "$db" {}
table "tbl" {
schema = schema.$db
column "precision_default" {
null = false
type = timestamp
default = sql("CURRENT_TIMESTAMP")
}
column "timestamp_4" {
null = false
type = timestamp(4)
default = sql("CURRENT_TIMESTAMP(4)")
}
column "timestamptz_4" {
null = false
type = timestamptz(4)
default = sql("CURRENT_TIMESTAMP(4)")
}
}
-- 1.sql --
Table "script_column_time_precision.tbl"
Column | Type | Collation | Nullable | Default
-------------------+--------------------------------+-----------+----------+----------------------
precision_default | timestamp without time zone | | not null | CURRENT_TIMESTAMP
timestamp_4 | timestamp(4) without time zone | | not null | CURRENT_TIMESTAMP(4)
timestamptz_4 | timestamp(4) with time zone | | not null | CURRENT_TIMESTAMP(4)
-- 2.hcl --
schema "$db" {}
table "tbl" {
schema = schema.$db
column "c1" {
type = timestamptz(1)
}
column "c2" {
type = timestamptz
}
column "c3" {
type = timestamptz(0)
}
column "c4" {
type = time
}
column "c5" {
type = time(1)
}
column "c6" {
type = timestamp
}
column "c7" {
type = timestamp(5)
}
column "c8" {
type = timetz(0)
}
column "c9" {
type = timetz
}
column "c10" {
type = timetz(6)
}
}
-- 2.sql --
Table "script_column_time_precision.tbl"
Column | Type | Collation | Nullable | Default
--------+--------------------------------+-----------+----------+---------
c1 | timestamp(1) with time zone | | not null |
c2 | timestamp with time zone | | not null |
c3 | timestamp(0) with time zone | | not null |
c4 | time without time zone | | not null |
c5 | time(1) without time zone | | not null |
c6 | timestamp without time zone | | not null |
c7 | timestamp(5) without time zone | | not null |
c8 | time(0) with time zone | | not null |
c9 | time with time zone | | not null |
c10 | time with time zone | | not null |
================================================
FILE: internal/integration/testdata/postgres/foreign-key-action.txtar
================================================
apply 1.hcl
cmpshow table_a table_a.sql
cmpshow table_b table_b.sql
cmpshow table_c table_c.sql
cmphcl 1.inspect.hcl
-- 1.hcl --
schema "script_foreign_key_action" {}
table "table_a" {
schema = schema.script_foreign_key_action
column "id" {
type = text
}
primary_key {
columns = [column.id]
}
}
table "table_b" {
schema = schema.script_foreign_key_action
column "id" {
type = text
}
column "table_a_id" {
type = text
}
primary_key {
columns = [column.id]
}
foreign_key "table_a_fk" {
columns = [column.table_a_id]
ref_columns = [table.table_a.column.id]
on_delete = "CASCADE"
on_update = "CASCADE"
}
}
table "table_c" {
schema = schema.script_foreign_key_action
column "id" {
type = text
}
column "table_a_id" {
type = text
}
primary_key {
columns = [column.id]
}
foreign_key "table_a_fk" {
columns = [column.table_a_id]
ref_columns = [table.table_a.column.id]
}
}
-- table_a.sql --
Table "script_foreign_key_action.table_a"
Column | Type | Collation | Nullable | Default
--------+------+-----------+----------+---------
id | text | | not null |
Indexes:
"table_a_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "script_foreign_key_action.table_b" CONSTRAINT "table_a_fk" FOREIGN KEY (table_a_id) REFERENCES script_foreign_key_action.table_a(id) ON UPDATE CASCADE ON DELETE CASCADE
TABLE "script_foreign_key_action.table_c" CONSTRAINT "table_a_fk" FOREIGN KEY (table_a_id) REFERENCES script_foreign_key_action.table_a(id)
-- table_b.sql --
Table "script_foreign_key_action.table_b"
Column | Type | Collation | Nullable | Default
------------+------+-----------+----------+---------
id | text | | not null |
table_a_id | text | | not null |
Indexes:
"table_b_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"table_a_fk" FOREIGN KEY (table_a_id) REFERENCES script_foreign_key_action.table_a(id) ON UPDATE CASCADE ON DELETE CASCADE
-- table_c.sql --
Table "script_foreign_key_action.table_c"
Column | Type | Collation | Nullable | Default
------------+------+-----------+----------+---------
id | text | | not null |
table_a_id | text | | not null |
Indexes:
"table_c_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"table_a_fk" FOREIGN KEY (table_a_id) REFERENCES script_foreign_key_action.table_a(id)
-- 1.inspect.hcl --
table "table_a" {
schema = schema.script_foreign_key_action
column "id" {
null = false
type = text
}
primary_key {
columns = [column.id]
}
}
table "table_b" {
schema = schema.script_foreign_key_action
column "id" {
null = false
type = text
}
column "table_a_id" {
null = false
type = text
}
primary_key {
columns = [column.id]
}
foreign_key "table_a_fk" {
columns = [column.table_a_id]
ref_columns = [table.table_a.column.id]
on_update = CASCADE
on_delete = CASCADE
}
}
table "table_c" {
schema = schema.script_foreign_key_action
column "id" {
null = false
type = text
}
column "table_a_id" {
null = false
type = text
}
primary_key {
columns = [column.id]
}
foreign_key "table_a_fk" {
columns = [column.table_a_id]
ref_columns = [table.table_a.column.id]
on_update = NO_ACTION
on_delete = NO_ACTION
}
}
schema "script_foreign_key_action" {
}
================================================
FILE: internal/integration/testdata/postgres/foreign-key.txtar
================================================
apply 1.hcl
cmpshow t1 t1.sql
cmpshow t2 t2.sql
cmphcl 1.inspect.hcl
-- 1.hcl --
schema "$db" {}
table "t1" {
schema = schema.$db
column "c1" {
null = false
type = integer
}
column "c2" {
null = true
type = integer
}
column "c3" {
null = true
type = integer
}
primary_key {
columns = [column.c1]
}
index "t1_c2_c3_idx" {
unique = true
columns = [column.c2, column.c3]
}
}
table "t2" {
schema = schema.$db
column "c1" {
null = false
type = integer
}
column "c2" {
null = true
type = integer
}
column "c3" {
null = true
type = integer
}
primary_key {
columns = [column.c1]
}
foreign_key "c2_c3_1" {
columns = [column.c2, column.c3]
ref_columns = [table.t1.column.c2, table.t1.column.c3]
on_update = NO_ACTION
on_delete = NO_ACTION
}
foreign_key "c2_c3_2" {
columns = [column.c2, column.c3]
ref_columns = [table.t1.column.c2, table.t1.column.c3]
on_update = NO_ACTION
on_delete = NO_ACTION
}
}
-- t1.sql --
Table "script_foreign_key.t1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
c1 | integer | | not null |
c2 | integer | | |
c3 | integer | | |
Indexes:
"t1_pkey" PRIMARY KEY, btree (c1)
"t1_c2_c3_idx" UNIQUE, btree (c2, c3)
Referenced by:
TABLE "script_foreign_key.t2" CONSTRAINT "c2_c3_1" FOREIGN KEY (c2, c3) REFERENCES script_foreign_key.t1(c2, c3)
TABLE "script_foreign_key.t2" CONSTRAINT "c2_c3_2" FOREIGN KEY (c2, c3) REFERENCES script_foreign_key.t1(c2, c3)
-- t2.sql --
Table "script_foreign_key.t2"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
c1 | integer | | not null |
c2 | integer | | |
c3 | integer | | |
Indexes:
"t2_pkey" PRIMARY KEY, btree (c1)
Foreign-key constraints:
"c2_c3_1" FOREIGN KEY (c2, c3) REFERENCES script_foreign_key.t1(c2, c3)
"c2_c3_2" FOREIGN KEY (c2, c3) REFERENCES script_foreign_key.t1(c2, c3)
-- 1.inspect.hcl --
table "t1" {
schema = schema.script_foreign_key
column "c1" {
null = false
type = integer
}
column "c2" {
null = true
type = integer
}
column "c3" {
null = true
type = integer
}
primary_key {
columns = [column.c1]
}
index "t1_c2_c3_idx" {
unique = true
columns = [column.c2, column.c3]
}
}
table "t2" {
schema = schema.script_foreign_key
column "c1" {
null = false
type = integer
}
column "c2" {
null = true
type = integer
}
column "c3" {
null = true
type = integer
}
primary_key {
columns = [column.c1]
}
foreign_key "c2_c3_1" {
columns = [column.c2, column.c3]
ref_columns = [table.t1.column.c2, table.t1.column.c3]
on_update = NO_ACTION
on_delete = NO_ACTION
}
foreign_key "c2_c3_2" {
columns = [column.c2, column.c3]
ref_columns = [table.t1.column.c2, table.t1.column.c3]
on_update = NO_ACTION
on_delete = NO_ACTION
}
}
schema "script_foreign_key" {
}
================================================
FILE: internal/integration/testdata/postgres/index-desc.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
# Drop the "DESC" option from the key part.
apply 2.hcl
cmpshow users 2.sql
# Use of "columns" instead of "on" should not trigger a change.
synced 2-no-change.hcl
apply 3.hcl
cmpshow users 3.sql
apply 4.hcl
cmpshow users 4.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "rank" {
type = int
}
index "rank_idx" {
on {
desc = true
column = column.rank
}
}
}
-- 1.sql --
Table "script_index_desc.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
rank | integer | | not null |
Indexes:
"rank_idx" btree (rank DESC)
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "rank" {
type = int
}
index "rank_idx" {
on {
column = table.users.column.rank
}
}
}
-- 2.sql --
Table "script_index_desc.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
rank | integer | | not null |
Indexes:
"rank_idx" btree (rank)
-- 2-no-change.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "rank" {
type = int
}
index "rank_idx" {
columns = [
table.users.column.rank,
]
}
}
-- 3.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "rank" {
type = int
}
column "score" {
type = int
}
index "rank_score_idx" {
on {
column = table.users.column.rank
}
on {
column = table.users.column.score
desc = true
}
}
}
-- 3.sql --
Table "script_index_desc.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
rank | integer | | not null |
score | integer | | not null |
Indexes:
"rank_score_idx" btree (rank, score DESC)
-- 4.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "rank" {
type = int
}
column "score" {
type = int
}
index "double_rank_desc_idx" {
on {
expr = "rank * 2"
desc = true
}
}
index "double_score_desc_idx" {
on {
expr = "score * 2"
desc = true
}
}
index "double_rank_idx" {
on {
expr = "rank * 2"
desc = false
}
}
index "double_score_idx" {
on {
expr = "score * 2"
desc = false
}
}
}
-- 4.sql --
Table "script_index_desc.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
rank | integer | | not null |
score | integer | | not null |
Indexes:
"double_rank_desc_idx" btree ((rank * 2) DESC)
"double_rank_idx" btree ((rank * 2))
"double_score_desc_idx" btree ((score * 2) DESC)
"double_score_idx" btree ((score * 2))
================================================
FILE: internal/integration/testdata/postgres/index-expr.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
apply 2.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "first_name" {
null = false
type = varchar(128)
}
column "last_name" {
null = false
type = varchar(128)
}
index "full_name" {
on {
expr = "first_name || ' ' || last_name"
}
}
}
-- 1.sql --
Table "script_index_expr.users"
Column | Type | Collation | Nullable | Default
------------+------------------------+-----------+----------+---------
first_name | character varying(128) | | not null |
last_name | character varying(128) | | not null |
Indexes:
"full_name" btree (((first_name::text || ' '::text) || last_name::text))
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "first_name" {
null = false
type = varchar(128)
}
column "last_name" {
null = false
type = varchar(128)
}
index "full_name" {
on {
expr = "first_name || '''s first name'"
}
}
}
-- 2.sql --
Table "script_index_expr.users"
Column | Type | Collation | Nullable | Default
------------+------------------------+-----------+----------+---------
first_name | character varying(128) | | not null |
last_name | character varying(128) | | not null |
Indexes:
"full_name" btree ((first_name::text || '''s first name'::text))
================================================
FILE: internal/integration/testdata/postgres/index-include.txtar
================================================
! only postgres10
# Create with INCLUDE.
apply 1.hcl
cmpshow users 1.sql
# Append one column to INCLUDE.
apply 2.hcl
cmpshow users 2.sql
# Remove one column from INCLUDE.
apply 3.hcl
cmpshow users 3.sql
# Remove INCLUDE.
apply 4.hcl
cmpshow users 4.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
null = false
type = text
}
column "active" {
null = true
type = boolean
}
index "users_name" {
columns = [column.name]
where = "active"
include = [column.active]
}
}
-- 1.sql --
Table "script_index_include.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
name | text | | not null |
active | boolean | | |
Indexes:
"users_name" btree (name) INCLUDE (active) WHERE active
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
null = false
type = text
}
column "active" {
null = true
type = boolean
}
column "version" {
null = true
type = text
}
index "users_name" {
columns = [column.name]
where = "active"
include = [column.active, column.version]
}
}
-- 2.sql --
Table "script_index_include.users"
Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
name | text | | not null |
active | boolean | | |
version | text | | |
Indexes:
"users_name" btree (name) INCLUDE (active, version) WHERE active
-- 3.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
null = false
type = text
}
column "active" {
null = true
type = boolean
}
column "version" {
null = true
type = text
}
index "users_name" {
columns = [column.name]
where = "active"
include = [column.version]
}
}
-- 3.sql --
Table "script_index_include.users"
Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
name | text | | not null |
active | boolean | | |
version | text | | |
Indexes:
"users_name" btree (name) INCLUDE (version) WHERE active
-- 4.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
null = false
type = text
}
column "active" {
null = true
type = boolean
}
column "version" {
null = true
type = text
}
index "users_name" {
columns = [column.name]
where = "active"
}
}
-- 4.sql --
Table "script_index_include.users"
Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
name | text | | not null |
active | boolean | | |
version | text | | |
Indexes:
"users_name" btree (name) WHERE active
================================================
FILE: internal/integration/testdata/postgres/index-issue-557.txtar
================================================
apply 1.hcl
cmpshow t1 t2 1.sql
-- 1.hcl --
schema "$db" {}
table "t1" {
schema = schema.$db
column "a" {
null = false
type = uuid
}
column "b" {
null = true
type = timestamp(6)
}
index "t1_a_b" {
on {
column = column.a
}
on {
desc = true
column = column.b
}
unique = true
}
}
table "t2" {
schema = schema.$db
column "a" {
null = false
type = uuid
}
primary_key {
columns = [column.a]
}
}
-- 1.sql --
Table "script_index_issue_557.t1"
Column | Type | Collation | Nullable | Default
--------+-----------------------------+-----------+----------+---------
a | uuid | | not null |
b | timestamp without time zone | | |
Indexes:
"t1_a_b" UNIQUE, btree (a, b DESC)
Table "script_index_issue_557.t2"
Column | Type | Collation | Nullable | Default
--------+------+-----------+----------+---------
a | uuid | | not null |
Indexes:
"t2_pkey" PRIMARY KEY, btree (a)
================================================
FILE: internal/integration/testdata/postgres/index-nulls-distinct.txtar
================================================
only postgres15
apply 1.hcl
cmphcl 1.inspect.hcl
cmpshow users 1.sql
# Change the nulls_distinct property of the index.
apply 2.hcl
cmphcl 2.inspect.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "script_index_nulls_distinct" {}
table "users" {
schema = schema.script_index_nulls_distinct
column "c" {
type = int
}
index "nulls_not_distinct" {
unique = true
columns = [column.c]
nulls_distinct = false
}
unique "nulls_not_distinct2" {
columns = [column.c]
nulls_distinct = false
}
}
-- 1.inspect.hcl --
table "users" {
schema = schema.script_index_nulls_distinct
column "c" {
null = false
type = integer
}
index "nulls_not_distinct" {
unique = true
columns = [column.c]
nulls_distinct = false
}
unique "nulls_not_distinct2" {
columns = [column.c]
nulls_distinct = false
}
}
schema "script_index_nulls_distinct" {
}
-- 1.sql --
Table "script_index_nulls_distinct.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
c | integer | | not null |
Indexes:
"nulls_not_distinct" UNIQUE, btree (c) NULLS NOT DISTINCT
"nulls_not_distinct2" UNIQUE CONSTRAINT, btree (c) NULLS NOT DISTINCT
-- 2.hcl --
schema "script_index_nulls_distinct" {}
table "users" {
schema = schema.script_index_nulls_distinct
column "c" {
type = int
}
index "nulls_not_distinct" {
unique = true
columns = [column.c]
}
}
-- 2.inspect.hcl --
table "users" {
schema = schema.script_index_nulls_distinct
column "c" {
null = false
type = integer
}
index "nulls_not_distinct" {
unique = true
columns = [column.c]
}
}
schema "script_index_nulls_distinct" {
}
-- 2.sql --
Table "script_index_nulls_distinct.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
c | integer | | not null |
Indexes:
"nulls_not_distinct" UNIQUE, btree (c)
================================================
FILE: internal/integration/testdata/postgres/index-operator-class.txtar
================================================
# Run this test only on 14 because tsvector_ops
# parameters are not supported in old versions.
only postgres14
apply 1.hcl
cmpshow pets 1.sql
apply 2.hcl
cmpshow pets 2.sql
cmphcl 2.inspect.hcl
apply 3.hcl
cmpshow logs 3.sql
apply 4.hcl
cmpshow tsv 4.sql
apply 5.hcl
cmpshow tsv 5.sql
-- 1.hcl --
schema "script_index_operator_class" {}
table "pets" {
schema = schema.$db
column "name" {
null = false
type = char(10)
}
index "name_idx1" {
on {
column = column.name
ops = bpchar_ops
}
}
index "name_idx2" {
on {
column = column.name
// Set a non-default operator class.
ops = bpchar_pattern_ops
}
}
}
-- 1.sql --
Table "script_index_operator_class.pets"
Column | Type | Collation | Nullable | Default
--------+---------------+-----------+----------+---------
name | character(10) | | not null |
Indexes:
"name_idx1" btree (name)
"name_idx2" btree (name bpchar_pattern_ops)
-- 2.hcl --
schema "script_index_operator_class" {}
table "pets" {
schema = schema.$db
column "name" {
null = false
type = char(10)
}
// Flip operator classes.
index "name_idx1" {
on {
column = column.name
ops = bpchar_pattern_ops
}
}
index "name_idx2" {
on {
column = column.name
ops = bpchar_ops
}
}
}
-- 2.sql --
Table "script_index_operator_class.pets"
Column | Type | Collation | Nullable | Default
--------+---------------+-----------+----------+---------
name | character(10) | | not null |
Indexes:
"name_idx1" btree (name bpchar_pattern_ops)
"name_idx2" btree (name)
-- 2.inspect.hcl --
table "pets" {
schema = schema.script_index_operator_class
column "name" {
null = false
type = character(10)
}
index "name_idx1" {
on {
column = column.name
ops = bpchar_pattern_ops
}
}
index "name_idx2" {
columns = [column.name]
}
}
schema "script_index_operator_class" {
}
-- 3.hcl --
schema "script_index_operator_class" {}
table "logs" {
schema = schema.$db
column "j" {
null = false
type = jsonb
}
index "j_idx" {
type = GIN
on {
column = column.j
ops = jsonb_path_ops
}
}
}
-- 3.sql --
Table "script_index_operator_class.logs"
Column | Type | Collation | Nullable | Default
--------+-------+-----------+----------+---------
j | jsonb | | not null |
Indexes:
"j_idx" gin (j jsonb_path_ops)
-- 4.hcl --
schema "script_index_operator_class" {}
table "tsv" {
schema = schema.$db
column "t" {
null = false
type = text
}
column "a" {
null = false
type = tsvector
}
index "a_idx" {
type = GiST
on {
column = column.a
ops = sql("tsvector_ops(siglen=8)")
}
}
}
-- 4.sql --
Table "script_index_operator_class.tsv"
Column | Type | Collation | Nullable | Default
--------+----------+-----------+----------+---------
t | text | | not null |
a | tsvector | | not null |
Indexes:
"a_idx" gist (a tsvector_ops (siglen='8'))
-- 5.hcl --
schema "script_index_operator_class" {}
table "tsv" {
schema = schema.$db
column "t" {
null = false
type = text
}
column "a" {
null = false
type = tsvector
}
index "a_idx" {
type = GiST
on {
column = column.a
ops = sql("tsvector_ops(siglen=9)")
}
}
}
-- 5.sql --
Table "script_index_operator_class.tsv"
Column | Type | Collation | Nullable | Default
--------+----------+-----------+----------+---------
t | text | | not null |
a | tsvector | | not null |
Indexes:
"a_idx" gist (a tsvector_ops (siglen='9'))
================================================
FILE: internal/integration/testdata/postgres/index-partial.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
apply 2.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
null = false
type = text
}
column "active" {
null = true
type = boolean
}
index "users_name" {
columns = [column.name]
where = "active"
}
}
-- 1.sql --
Table "script_index_partial.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
name | text | | not null |
active | boolean | | |
Indexes:
"users_name" btree (name) WHERE active
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
null = false
type = text
}
column "active" {
null = true
type = boolean
}
index "users_name" {
columns = [column.name]
where = "active AND name <> ''"
}
}
-- 2.sql --
Table "script_index_partial.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
name | text | | not null |
active | boolean | | |
Indexes:
"users_name" btree (name) WHERE active AND name <> ''::text
================================================
FILE: internal/integration/testdata/postgres/index-type-brin.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
# Add the "page_per_range" storage parameter.
apply 2.hcl
cmpshow users 2.sql
# Change the "page_per_range" storage parameter.
apply 3.hcl
cmpshow users 3.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "c" {
null = false
type = int
}
index "users_c" {
type = BRIN
columns = [column.c]
}
}
-- 1.sql --
Table "script_index_type_brin.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
c | integer | | not null |
Indexes:
"users_c" brin (c)
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "c" {
null = false
type = int
}
index "users_c" {
type = BRIN
columns = [column.c]
page_per_range = 2
}
}
-- 2.sql --
Table "script_index_type_brin.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
c | integer | | not null |
Indexes:
"users_c" brin (c) WITH (pages_per_range='2')
-- 3.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "c" {
null = false
type = int
}
index "users_c" {
type = BRIN
columns = [column.c]
page_per_range = 3
}
}
-- 3.sql --
Table "script_index_type_brin.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
c | integer | | not null |
Indexes:
"users_c" brin (c) WITH (pages_per_range='3')
================================================
FILE: internal/integration/testdata/postgres/index-type.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
# Change index type.
apply 2.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
null = false
type = text
}
column "data" {
null = true
type = jsonb
}
index "users_name" {
type = HASH
columns = [column.name]
}
index "users_data" {
type = GIN
columns = [column.data]
}
}
-- 1.sql --
Table "script_index_type.users"
Column | Type | Collation | Nullable | Default
--------+-------+-----------+----------+---------
name | text | | not null |
data | jsonb | | |
Indexes:
"users_data" gin (data)
"users_name" hash (name)
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "name" {
null = false
type = text
}
column "data" {
null = true
type = jsonb
}
index "users_name" {
columns = [column.name]
# Index without "using" defaults to BTREE.
}
index "users_data" {
columns = [column.data]
}
}
-- 2.sql --
Table "script_index_type.users"
Column | Type | Collation | Nullable | Default
--------+-------+-----------+----------+---------
name | text | | not null |
data | jsonb | | |
Indexes:
"users_data" btree (data)
"users_name" btree (name)
================================================
FILE: internal/integration/testdata/postgres/index-unique-constraint.txtar
================================================
# Create table with UNIQUE constraint. i.e. implicit unique index.
execsql 'CREATE TABLE script_index_unique_constraint.users (name text, last text, nickname text UNIQUE, UNIQUE(name, last))'
cmphcl 1.inspect.hcl
# Dropping the unique index on the "nickname" column should drop the constraint as well.
apply 2.hcl
cmpshow users 2.sql
apply 3.hcl
cmpshow users 3.sql
atlas schema clean -u URL --auto-approve
atlas schema inspect -u file://4.sql --dev-url URL > got
cmp got 4.inspect.hcl
-- 1.inspect.hcl --
table "users" {
schema = schema.script_index_unique_constraint
column "name" {
null = true
type = text
}
column "last" {
null = true
type = text
}
column "nickname" {
null = true
type = text
}
unique "users_name_last_key" {
columns = [column.name, column.last]
}
unique "users_nickname_key" {
columns = [column.nickname]
}
}
schema "script_index_unique_constraint" {
}
-- 2.hcl --
table "users" {
schema = schema.script_index_unique_constraint
column "name" {
null = true
type = text
}
column "last" {
null = true
type = text
}
column "nickname" {
null = true
type = text
}
unique "users_name_last_key" {
columns = [column.name, column.last]
}
}
schema "script_index_unique_constraint" {
}
-- 2.sql --
Table "script_index_unique_constraint.users"
Column | Type | Collation | Nullable | Default
----------+------+-----------+----------+---------
name | text | | |
last | text | | |
nickname | text | | |
Indexes:
"users_name_last_key" UNIQUE CONSTRAINT, btree (name, last)
-- 3.hcl --
table "users" {
schema = schema.script_index_unique_constraint
column "name" {
null = true
type = text
}
column "last" {
null = true
type = text
}
column "nickname" {
null = true
type = text
}
}
schema "script_index_unique_constraint" {
}
-- 3.sql --
Table "script_index_unique_constraint.users"
Column | Type | Collation | Nullable | Default
----------+------+-----------+----------+---------
name | text | | |
last | text | | |
nickname | text | | |
-- 4.sql --
create table t1(a int primary key, b int unique);
create table t0(b int primary key references t1(b));
create table t2(c int primary key references t1(b));
create table d(c int unique references t1(b));
-- 4.inspect.hcl --
table "d" {
schema = schema.script_index_unique_constraint
column "c" {
null = true
type = integer
}
foreign_key "d_c_fkey" {
columns = [column.c]
ref_columns = [table.t1.column.b]
on_update = NO_ACTION
on_delete = NO_ACTION
}
unique "d_c_key" {
columns = [column.c]
}
}
table "t0" {
schema = schema.script_index_unique_constraint
column "b" {
null = false
type = integer
}
primary_key {
columns = [column.b]
}
foreign_key "t0_b_fkey" {
columns = [column.b]
ref_columns = [table.t1.column.b]
on_update = NO_ACTION
on_delete = NO_ACTION
}
}
table "t1" {
schema = schema.script_index_unique_constraint
column "a" {
null = false
type = integer
}
column "b" {
null = true
type = integer
}
primary_key {
columns = [column.a]
}
unique "t1_b_key" {
columns = [column.b]
}
}
table "t2" {
schema = schema.script_index_unique_constraint
column "c" {
null = false
type = integer
}
primary_key {
columns = [column.c]
}
foreign_key "t2_c_fkey" {
columns = [column.c]
ref_columns = [table.t1.column.b]
on_update = NO_ACTION
on_delete = NO_ACTION
}
}
schema "script_index_unique_constraint" {
}
================================================
FILE: internal/integration/testdata/postgres/primary-key.txtar
================================================
only postgres15
# Create table.
apply 1.hcl
cmpshow users 1.sql
# Add a primary-key.
apply 2.hcl
cmpshow users 2.sql
# Modify the primary-key include columns.
apply 3.hcl
cmpshow users 3.sql
# Drop the primary-key.
apply 1.hcl
cmpshow users 1.sql
-- 1.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "id" {
null = false
type = int
}
column "c" {
null = true
type = int
}
}
-- 1.sql --
Table "script_primary_key.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id | integer | | not null |
c | integer | | |
-- 2.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "id" {
null = false
type = int
}
column "c" {
null = true
type = int
}
primary_key {
columns = [column.id]
}
}
-- 2.sql --
Table "script_primary_key.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id | integer | | not null |
c | integer | | |
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
-- 3.hcl --
schema "$db" {}
table "users" {
schema = schema.$db
column "id" {
null = false
type = int
}
column "c" {
null = true
type = int
}
primary_key {
columns = [column.id]
include = [column.c]
}
}
-- 3.sql --
Table "script_primary_key.users"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id | integer | | not null |
c | integer | | |
Indexes:
"users_pkey" PRIMARY KEY, btree (id) INCLUDE (c)
================================================
FILE: internal/integration/testdata/postgres/table-checks.txtar
================================================
# Inspect SQL format.
atlas schema inspect --url file://schema.sql --dev-url URL --format '{{ sql . " " }}' > got
cmp schema.inspected.sql got
# Inspect HCL format.
atlas schema inspect --url file://schema.sql --dev-url URL > got
cmp schema.inspected.hcl got
atlas migrate diff v1 --to file://schema.sql --dev-url URL --format '{{ sql . " " }}'
cmpmig 0 migration.v1.sql
atlas migrate diff v1-check --to file://schema.sql --dev-url URL --format '{{ sql . " " }}'
stdout 'The migration directory is synced with the desired state, no changes to be made'
atlas migrate diff v2 --to file://schema.v2.sql --dev-url URL --format '{{ sql . " " }}'
cmpmig 1 migration.v2.sql
atlas migrate diff v2-check --to file://schema.v2.sql --dev-url URL --format '{{ sql . " " }}'
stdout 'The migration directory is synced with the desired state, no changes to be made'
atlas migrate diff v3 --to file://schema.v3.sql --dev-url URL --format '{{ sql . " " }}'
cmpmig 2 migration.v3.sql
atlas migrate diff v3-check --to file://schema.v3.sql --dev-url URL --format '{{ sql . " " }}'
stdout 'The migration directory is synced with the desired state, no changes to be made'
-- schema.sql --
create table t1 (
a int constraint c1 check (a > 0),
b int constraint c2 check (b > 0),
constraint c3 check (a < b)
);
create table t2 (
a int constraint c1 check (a > 0),
c int constraint c4 check (c > 0),
constraint c5 check (a < c)
);
-- schema.inspected.sql --
-- Create "t1" table
CREATE TABLE "t1" (
"a" integer NULL,
"b" integer NULL,
CONSTRAINT "c1" CHECK (a > 0),
CONSTRAINT "c2" CHECK (b > 0),
CONSTRAINT "c3" CHECK (a < b)
);
-- Create "t2" table
CREATE TABLE "t2" (
"a" integer NULL,
"c" integer NULL,
CONSTRAINT "c1" CHECK (a > 0),
CONSTRAINT "c4" CHECK (c > 0),
CONSTRAINT "c5" CHECK (a < c)
);
-- schema.inspected.hcl --
table "t1" {
schema = schema.script_table_checks
column "a" {
null = true
type = integer
}
column "b" {
null = true
type = integer
}
check "c1" {
expr = "(a > 0)"
}
check "c2" {
expr = "(b > 0)"
}
check "c3" {
expr = "(a < b)"
}
}
table "t2" {
schema = schema.script_table_checks
column "a" {
null = true
type = integer
}
column "c" {
null = true
type = integer
}
check "c1" {
expr = "(a > 0)"
}
check "c4" {
expr = "(c > 0)"
}
check "c5" {
expr = "(a < c)"
}
}
schema "script_table_checks" {
}
-- migration.v1.sql --
-- Create "t1" table
CREATE TABLE "t1" (
"a" integer NULL,
"b" integer NULL,
CONSTRAINT "c1" CHECK (a > 0),
CONSTRAINT "c2" CHECK (b > 0),
CONSTRAINT "c3" CHECK (a < b)
);
-- Create "t2" table
CREATE TABLE "t2" (
"a" integer NULL,
"c" integer NULL,
CONSTRAINT "c1" CHECK (a > 0),
CONSTRAINT "c4" CHECK (c > 0),
CONSTRAINT "c5" CHECK (a < c)
);
-- schema.v2.sql --
create table t1 (
a int constraint c1 check (a > 1),
b int constraint c2 check (b > 1),
constraint c3 check (a < b)
);
create table t2 (
a int constraint c1 check (a > 1),
c int constraint c4 check (c > 1),
constraint c5 check (a < c)
);
-- migration.v2.sql --
-- Modify "t1" table
ALTER TABLE "t1" DROP CONSTRAINT "c1", ADD CONSTRAINT "c1" CHECK (a > 1), DROP CONSTRAINT "c2", ADD CONSTRAINT "c2" CHECK (b > 1);
-- Modify "t2" table
ALTER TABLE "t2" DROP CONSTRAINT "c1", ADD CONSTRAINT "c1" CHECK (a > 1), DROP CONSTRAINT "c4", ADD CONSTRAINT "c4" CHECK (c > 1);
-- schema.v3.sql --
create table t1 (
a int constraint c1 check (a > 1),
b int constraint c2 check (b > 1),
-- Rename constraint.
constraint c4 check (a < b)
);
create table t2 (
a int constraint c1 check (a > 1),
c int constraint c4 check (c > 1),
-- Rename constraint.
constraint c6 check (a < c)
);
-- migration.v3.sql --
-- Modify "t1" table
ALTER TABLE "t1" DROP CONSTRAINT "c3", ADD CONSTRAINT "c4" CHECK (a < b);
-- Modify "t2" table
ALTER TABLE "t2" DROP CONSTRAINT "c5", ADD CONSTRAINT "c6" CHECK (a < c);
================================================
FILE: internal/integration/testdata/postgres/table-partition.txtar
================================================
apply 1.hcl
cmpshow logs 1.sql
# Changing partitioned table is not allowed.
! apply 2.hcl 'partition key of table "logs" cannot be changed from PARTITION BY LIST ("value") to PARTITION BY RANGE ("a", (b * (a % 2))) (drop and add is required)'
# Drop all tables.
apply drop.hcl
# Recreate partitioned table.
apply 2.hcl
cmpshow logs 2.sql
# Drop all tables.
apply drop.hcl
apply 3.hcl
cmpshow measurement 3.sql
cmphcl 3.inspect.hcl
execsql 'CREATE TABLE measurement_y2006m02 PARTITION OF $db.measurement FOR VALUES FROM (''2006-02-01'') TO (''2006-03-01'')'
cmpshow measurement 3.partition.sql
# Drop all tables.
apply drop.hcl
apply 4.hcl
cmpshow metrics 4.sql
cmphcl 4.inspect.hcl
-- 1.hcl --
schema "$db" {}
table "logs" {
schema = schema.$db
column "value" {
null = false
type = integer
}
partition {
type = LIST
columns = [column.value]
}
}
-- postgres10/1.sql --
Table "script_table_partition.logs"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
value | integer | | not null |
Partition key: LIST (value)
-- postgres11/1.sql --
Table "script_table_partition.logs"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
value | integer | | not null |
Partition key: LIST (value)
Number of partitions: 0
-- 1.sql --
Partitioned table "script_table_partition.logs"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
value | integer | | not null |
Partition key: LIST (value)
Number of partitions: 0
-- 2.hcl --
schema "$db" {}
table "logs" {
schema = schema.$db
column "a" {
null = false
type = integer
}
column "b" {
null = false
type = integer
}
partition {
type = RANGE
by {
column = column.a
}
by {
expr = "b * (a % 2)"
}
}
}
-- postgres10/2.sql --
Table "script_table_partition.logs"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | not null |
b | integer | | not null |
Partition key: RANGE (a, ((b * (a % 2))))
-- postgres11/2.sql --
Table "script_table_partition.logs"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | not null |
b | integer | | not null |
Partition key: RANGE (a, ((b * (a % 2))))
Number of partitions: 0
-- 2.sql --
Partitioned table "script_table_partition.logs"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | not null |
b | integer | | not null |
Partition key: RANGE (a, ((b * (a % 2))))
Number of partitions: 0
-- 3.hcl --
schema "$db" {}
# The partitioned table from the PostgreSQL doc.
table "measurement" {
schema = schema.$db
column "city_id" {
null = false
type = integer
}
column "logdate" {
null = false
type = date
}
column "peaktemp" {
null = true
type = int
}
column "unitsales" {
null = true
type = int
}
partition {
type = RANGE
columns = [column.logdate]
}
}
-- postgres10/3.sql --
Table "script_table_partition.measurement"
Column | Type | Collation | Nullable | Default
-----------+---------+-----------+----------+---------
city_id | integer | | not null |
logdate | date | | not null |
peaktemp | integer | | |
unitsales | integer | | |
Partition key: RANGE (logdate)
-- postgres11/3.sql --
Table "script_table_partition.measurement"
Column | Type | Collation | Nullable | Default
-----------+---------+-----------+----------+---------
city_id | integer | | not null |
logdate | date | | not null |
peaktemp | integer | | |
unitsales | integer | | |
Partition key: RANGE (logdate)
Number of partitions: 0
-- 3.sql --
Partitioned table "script_table_partition.measurement"
Column | Type | Collation | Nullable | Default
-----------+---------+-----------+----------+---------
city_id | integer | | not null |
logdate | date | | not null |
peaktemp | integer | | |
unitsales | integer | | |
Partition key: RANGE (logdate)
Number of partitions: 0
-- postgres10/3.partition.sql --
Table "script_table_partition.measurement"
Column | Type | Collation | Nullable | Default
-----------+---------+-----------+----------+---------
city_id | integer | | not null |
logdate | date | | not null |
peaktemp | integer | | |
unitsales | integer | | |
Partition key: RANGE (logdate)
Number of partitions: 1 (Use \d+ to list them.)
-- postgres11/3.partition.sql --
Table "script_table_partition.measurement"
Column | Type | Collation | Nullable | Default
-----------+---------+-----------+----------+---------
city_id | integer | | not null |
logdate | date | | not null |
peaktemp | integer | | |
unitsales | integer | | |
Partition key: RANGE (logdate)
Number of partitions: 1 (Use \d+ to list them.)
-- 3.partition.sql --
Partitioned table "script_table_partition.measurement"
Column | Type | Collation | Nullable | Default
-----------+---------+-----------+----------+---------
city_id | integer | | not null |
logdate | date | | not null |
peaktemp | integer | | |
unitsales | integer | | |
Partition key: RANGE (logdate)
Number of partitions: 1 (Use \d+ to list them.)
-- 3.inspect.hcl --
table "measurement" {
schema = schema.script_table_partition
column "city_id" {
null = false
type = integer
}
column "logdate" {
null = false
type = date
}
column "peaktemp" {
null = true
type = integer
}
column "unitsales" {
null = true
type = integer
}
partition {
type = RANGE
columns = [column.logdate]
}
}
schema "script_table_partition" {
}
-- 4.hcl --
schema "$db" {}
table "metrics" {
schema = schema.$db
column "x" {
null = false
type = integer
}
column "y" {
null = false
type = integer
}
partition {
type = RANGE
by {
column = column.x
}
by {
expr = "floor(x)"
}
by {
expr = "y * 2"
}
by {
expr = "floor(y)"
}
}
}
-- postgres10/4.sql --
Table "script_table_partition.metrics"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
x | integer | | not null |
y | integer | | not null |
Partition key: RANGE (x, floor((x)::double precision), ((y * 2)), floor((y)::double precision))
-- postgres11/4.sql --
Table "script_table_partition.metrics"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
x | integer | | not null |
y | integer | | not null |
Partition key: RANGE (x, floor((x)::double precision), ((y * 2)), floor((y)::double precision))
Number of partitions: 0
-- 4.sql --
Partitioned table "script_table_partition.metrics"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
x | integer | | not null |
y | integer | | not null |
Partition key: RANGE (x, floor((x)::double precision), ((y * 2)), floor((y)::double precision))
Number of partitions: 0
-- 4.inspect.hcl --
table "metrics" {
schema = schema.script_table_partition
column "x" {
null = false
type = integer
}
column "y" {
null = false
type = integer
}
partition {
type = RANGE
by {
column = column.x
}
by {
expr = "floor((x)::double precision)"
}
by {
expr = "(y * 2)"
}
by {
expr = "floor((y)::double precision)"
}
}
}
schema "script_table_partition" {
}
-- drop.hcl --
schema "$db" {}
================================================
FILE: internal/integration/testdata/sqlite/autoincrement.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
-- 1.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "id" {
null = false
type = integer
auto_increment = true
}
primary_key {
columns = [column.id]
}
}
-- 1.sql --
CREATE TABLE `users` (`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT)
================================================
FILE: internal/integration/testdata/sqlite/cli-apply-multifile.txtar
================================================
atlas schema apply -f users.hcl -f schema.hcl -u URL --auto-approve
cmpshow users expected.sql
-- users.hcl --
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
column "status" {
null = true
type = text
default = "hello"
}
}
-- schema.hcl --
schema "main" {
}
-- expected.sql --
CREATE TABLE `users` (
`id` int NOT NULL,
`status` text NULL DEFAULT 'hello'
)
================================================
FILE: internal/integration/testdata/sqlite/cli-apply-project-multifile.txtar
================================================
atlas schema apply --env local --auto-approve
cmpshow users expected.sql
-- atlas.hcl --
env "local" {
url = "URL"
src = "./schema"
def_val = "hello"
}
-- schema/vars.hcl --
variable "def_val" {
type = string
}
-- schema/table.hcl --
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
column "status" {
null = true
type = text
default = var.def_val
}
}
-- schema/schema.hcl --
schema "main" {
}
-- expected.sql --
CREATE TABLE `users` (
`id` int NOT NULL,
`status` text NULL DEFAULT 'hello'
)
================================================
FILE: internal/integration/testdata/sqlite/cli-apply-vars.txtar
================================================
! atlas schema apply --env local --auto-approve
stderr 'missing value for required variable "def_val"'
atlas schema apply --env local_with_vals --auto-approve
cmpshow users expected.sql
-- atlas.hcl --
env "local" {
url = "URL"
src = "./1.hcl"
}
env "local_with_vals" {
url = "URL"
src = "./1.hcl"
def_val = "hello"
}
-- 1.hcl --
variable "def_val" {
type = string
}
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
column "status" {
null = true
type = text
default = var.def_val
}
}
schema "main" {
}
-- expected.sql --
CREATE TABLE `users` (
`id` int NOT NULL,
`status` text NULL DEFAULT 'hello'
)
================================================
FILE: internal/integration/testdata/sqlite/cli-inspect.txtar
================================================
apply 1.hcl
# test url flag
atlas schema inspect -u URL > inspected.hcl
cmp inspected.hcl 1.hcl
# test exclude flag on table.
atlas schema inspect -u URL --exclude "users" > inspected.hcl
cmp inspected.hcl notable.hcl
# test exclude flag on column.
atlas schema inspect -u URL --exclude "*.[ab]*" > inspected.hcl
cmp inspected.hcl id.hcl
# test exclude flag on column.
atlas schema inspect -u URL --exclude "*.*" > inspected.hcl
cmp inspected.hcl nocolumn.hcl
-- 1.hcl --
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
column "a" {
null = false
type = int
}
column "b" {
null = false
type = int
}
column "ab" {
null = false
type = int
}
column "ac" {
null = false
type = uint64
}
}
schema "main" {
}
-- empty.hcl --
-- notable.hcl --
schema "main" {
}
-- id.hcl --
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
}
schema "main" {
}
-- nocolumn.hcl --
table "users" {
schema = schema.main
}
schema "main" {
}
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-apply.txtar
================================================
! atlas migrate apply
stderr 'Error: checksum file not found'
stdout 'You have a checksum error in your migration directory.'
stdout 'atlas migrate hash'
atlas migrate hash
# Apply all of them
atlas migrate apply --url URL
stdout 'Migrating to version 2 \(2 migrations in total\):'
stdout '-- migrating version 1'
stdout '-> CREATE TABLE `users` \('
stdout ' `id` integer NOT NULL,'
stdout ' `age` integer NOT NULL,'
stdout ' `name` TEXT NOT NULL,'
stdout ' PRIMARY KEY \(`id`\)'
stdout '\);'
stdout '-- migrating version 2'
stdout '-> CREATE TABLE `pets` \(`id` integer NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY \(`id`\)\);'
stdout '-- 2 migrations'
stdout '-- 2 sql statements'
cmpshow users users.sql
cmpshow pets pets.sql
atlas migrate apply --url URL 1
stdout 'No migration files to execute'
clearSchema
# Apply one by one
atlas migrate apply --url URL 1
stdout 'Migrating to version 1 \(1 migrations in total\):'
cmpshow users users.sql
atlas migrate apply --url URL 1
stdout 'Migrating to version 2 from 1 \(1 migrations in total\):'
cmpshow users users.sql
cmpshow pets pets.sql
atlas migrate apply --url URL 1
stdout 'No migration files to execute'
clearSchema
# Move the broken migration into the migrations directory and check the different transaction modes.
cp broken.sql migrations/3_third.sql
atlas migrate hash
! atlas migrate apply --url URL --tx-mode invalid
stderr 'unknown tx-mode "invalid"'
# Test --tx-mode all
! atlas migrate apply --url URL --tx-mode all
stderr 'executing statement "THIS IS A FAILING STATEMENT;" from version "3"'
atlas schema inspect --url URL --exclude atlas_schema_revisions
cmp stdout empty.hcl
# Apply one migration, after rolling everything back, the first revision must still exist.
atlas migrate apply --url URL 1
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users
cmp stdout empty.hcl
cmpshow users users.sql
! atlas migrate apply --url URL --tx-mode all
stderr 'executing statement "THIS IS A FAILING STATEMENT;" from version "3"'
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users
cmp stdout empty.hcl
# If the broken migration is gone, we can apply everything without any problems.
rm migrations/3_third.sql
atlas migrate hash
atlas migrate apply --url URL --revisions-schema $db
cmpshow users users.sql
cmpshow pets pets.sql
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets
cmp stdout empty.hcl
clearSchema
# Test --tx-mode file
cp broken.sql migrations/3_third.sql
atlas migrate hash
! atlas migrate apply --url URL --tx-mode file
stderr 'executing statement "THIS IS A FAILING STATEMENT;" from version "3"'
atlas schema inspect --url URL --exclude atlas_schema_revisions
cmpshow users users.sql
cmpshow pets pets.sql
# Table "broken" does not exist since we rolled back that migration.
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets
cmp stdout empty.hcl
# If the broken migration is gone, we can apply everything without any problems.
rm migrations/3_third.sql
atlas migrate hash
atlas migrate apply --url URL --revisions-schema $db
cmpshow users users.sql
cmpshow pets pets.sql
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets
cmp stdout empty.hcl
clearSchema
# Test --tx-mode none
cp broken.sql migrations/3_third.sql
atlas migrate hash
! atlas migrate apply --url URL --tx-mode none
stderr 'executing statement "THIS IS A FAILING STATEMENT;" from version "3"'
atlas schema inspect --url URL --exclude atlas_schema_revisions
cmpshow users users.sql
cmpshow pets pets.sql
# Table "broken" does exist since we do not have transactions.
atlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets
cmp stdout broken.hcl
-- migrations/1_first.sql --
CREATE TABLE `users` (
`id` integer NOT NULL,
`age` integer NOT NULL,
`name` TEXT NOT NULL,
PRIMARY KEY (`id`)
);
-- migrations/2_second.sql --
CREATE TABLE `pets` (`id` integer NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY (`id`));
-- broken.sql --
CREATE TABLE `broken` (`id` integer);
THIS IS A FAILING STATEMENT;
-- empty.hcl --
schema "main" {
}
-- broken.hcl --
table "broken" {
schema = schema.main
column "id" {
null = true
type = integer
}
}
schema "main" {
}
-- users.sql --
CREATE TABLE `users` (
`id` integer NOT NULL,
`age` integer NOT NULL,
`name` TEXT NOT NULL,
PRIMARY KEY (`id`)
)
-- pets.sql --
CREATE TABLE `pets` (`id` integer NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY (`id`))
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-diff-datasrc-hcl-paths.txtar
================================================
atlas migrate diff --env local
cmpmig 0 expected.sql
-- atlas.hcl --
data "hcl_schema" "app" {
paths = glob("schema-*.hcl")
vars = {
default_value = "unknown"
}
}
env "local" {
src = data.hcl_schema.app.url
dev = "sqlite://dev?mode=memory&_fk=1"
}
-- schema-1.hcl --
schema "main" {}
table "pets" {
schema = schema.main
column "name" {
null = false
type = text
default = var.default_value
}
column "owner_id" {
type = integer
}
foreign_key "owner_id" {
columns = [column.owner_id]
ref_columns = [table.users.column.id]
on_update = NO_ACTION
on_delete = NO_ACTION
}
}
-- schema-2.hcl --
variable "default_value" {
type = string
}
table "users" {
schema = schema.main
column "id" {
null = true
type = integer
}
column "name" {
null = false
type = text
default = var.default_value
}
}
-- expected.sql --
-- Create "pets" table
CREATE TABLE `pets` (`name` text NOT NULL DEFAULT 'unknown', `owner_id` integer NOT NULL, CONSTRAINT `owner_id` FOREIGN KEY (`owner_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION);
-- Create "users" table
CREATE TABLE `users` (`id` integer NULL, `name` text NOT NULL DEFAULT 'unknown');
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-diff-datasrc-hcl.txtar
================================================
atlas migrate diff --env local
cmpmig 0 expected.sql
-- atlas.hcl --
data "hcl_schema" "app" {
path = "schema.hcl"
vars = {
default_value = "unknown"
}
}
env "local" {
src = data.hcl_schema.app.url
dev = "sqlite://dev?mode=memory&_fk=1"
}
-- schema.hcl --
variable "default_value" {
type = string
}
schema "main" {}
table "users" {
schema = schema.main
column "name" {
null = false
type = text
default = var.default_value
}
}
-- expected.sql --
-- Create "users" table
CREATE TABLE `users` (`name` text NOT NULL DEFAULT 'unknown');
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-diff-minimal-env.txtar
================================================
atlas migrate diff --env local
cmpmig 0 diff.sql
-- atlas.hcl --
env "local" {
src = "1.hcl"
dev = "sqlite://devdb"
}
-- 1.hcl --
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
}
schema "main" {
}
-- diff.sql --
-- Create "users" table
CREATE TABLE `users` (`id` int NOT NULL);
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-diff-multifile.txtar
================================================
! atlas migrate diff --dev-url sqlite://devdb --to file://schema/ --to other://scheme --dir file://migrations
stderr 'got mixed --to url schemes'
! atlas migrate diff --dev-url sqlite://devdb --to mysql://localhost/x --to mysql://localhost/y --dir file://migrations
stderr 'got multiple --to urls of scheme'
atlas migrate diff --dev-url sqlite://devdb --to file://schema/ --dir file://migrations
cmpmig 0 diff.sql
# reset dir
exec rm -rf migrations/
atlas migrate diff --dev-url sqlite://devdb --to file://schema/schema.hcl --to file://schema/table.hcl --dir file://migrations
cmpmig 0 diff.sql
-- schema/schema.hcl --
schema "main" {
}
-- schema/table.hcl --
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
}
-- diff.sql --
-- Create "users" table
CREATE TABLE `users` (`id` int NOT NULL);
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-diff-sql.txtar
================================================
atlas migrate diff --dev-url sqlite://dev --to file://schema.sql --dir file://migrations
cmpmig 0 diff.sql
atlas migrate diff --dev-url sqlite://dev --to file://schema.sql --dir file://migrations
stdout 'The migration directory is synced with the desired state, no changes to be made'
atlas schema diff --dev-url sqlite://dev?mode=memory --from file://migrations --to file://schema.sql --exclude atlas_schema_revisions
stdout 'Schemas are synced, no changes to be made.'
-- schema.sql --
-- Create "records" table
CREATE TABLE IF NOT EXISTS `records` (
`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT,
`name` varchar(255) NOT NULL DEFAULT '' UNIQUE,
`price` decimal NOT NULL DEFAULT 0
);
CREATE INDEX `records_price` ON `records` (`price`);
-- Create "categories" table
CREATE TABLE IF NOT EXISTS categories (
id INTEGER NOT NULL PRIMARY KEY,
category_name VARCHAR(255) NOT NULL
);
-- Create "products" table
CREATE TABLE IF NOT EXISTS products (
id INTEGER NOT NULL PRIMARY KEY,
product_name VARCHAR(255) NOT NULL UNIQUE,
price DECIMAL(10,2) NOT NULL,
category_id INTEGER,
FOREIGN KEY (category_id) REFERENCES categories (id) ON DELETE SET NULL
);
-- diff.sql --
-- Create "records" table
CREATE TABLE `records` (`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT, `name` varchar NOT NULL DEFAULT '', `price` decimal NOT NULL DEFAULT 0);
-- Create index "records_name" to table: "records"
CREATE UNIQUE INDEX `records_name` ON `records` (`name`);
-- Create index "records_price" to table: "records"
CREATE INDEX `records_price` ON `records` (`price`);
-- Create "categories" table
CREATE TABLE `categories` (`id` integer NOT NULL, `category_name` varchar NOT NULL, PRIMARY KEY (`id`));
-- Create "products" table
CREATE TABLE `products` (`id` integer NOT NULL, `product_name` varchar NOT NULL, `price` decimal NOT NULL, `category_id` integer NULL, PRIMARY KEY (`id`), CONSTRAINT `0` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON UPDATE NO ACTION ON DELETE SET NULL);
-- Create index "products_product_name" to table: "products"
CREATE UNIQUE INDEX `products_product_name` ON `products` (`product_name`);
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-diff.txtar
================================================
exec mkdir migrations
! atlas migrate diff --to file://1.hcl --dir file://migrations
stderr '"dev-url" not set'
! atlas migrate diff --dev-url sqlite://devdb --dir file://migrations
stderr '"to" not set'
atlas migrate diff --dev-url sqlite://devdb --to file://1.hcl --dir file://migrations
cmpmig 0 diff.sql
-- 1.hcl --
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
}
schema "main" {
}
-- diff.sql --
-- Create "users" table
CREATE TABLE `users` (`id` int NOT NULL);
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-lint-add-notnull.txtar
================================================
atlas migrate lint --dir file://migrations --dev-url URL --latest=2
stdout 'Analyzing changes until version 2 \(2 migrations in total\):'
stdout ''
stdout ' -- analyzing version 1'
stdout ' -- no diagnostics found'
stdout ' -- ok \(.+\)'
stdout ''
stdout ' -- analyzing version 2'
stdout ' -- data dependent changes detected:'
stdout ' -- L1: Adding a non-nullable "int" column "c2" will fail in case table "users" is not empty'
stdout ' https://atlasgo.io/lint/analyzers#MF103'
stdout ' -- ok \(.+\)'
stdout ''
stdout ' -------------------------'
stdout ' -- .+'
stdout ' -- 1 version ok, 1 with warnings'
stdout ' -- 4 schema changes'
stdout ' -- 1 diagnostic'
-- migrations/1.sql --
CREATE TABLE users (id int);
/* Adding a not-null column without default to a table created in this file should not report. */
ALTER TABLE users ADD COLUMN c1 int NOT NULL;
-- migrations/2.sql --
ALTER TABLE users ADD COLUMN c2 int NOT NULL;
ALTER TABLE users ADD COLUMN c3 int NOT NULL DEFAULT 1;
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-lint-destructive.txtar
================================================
# Expect the command to fail; exit code 1.
! atlas migrate lint --dir file://migrations --dev-url URL --latest=1
stdout 'Analyzing changes from version 2 to 3 \(1 migration in total\):'
stdout ''
stdout ' -- analyzing version 3'
stdout ' -- destructive changes detected:'
stdout ' -- L1: Dropping table "pets" https://atlasgo.io/lint/analyzers#DS102'
stdout ' -- suggested fix:'
stdout ' -> Add a pre-migration check to ensure table "pets" is empty before dropping it'
stdout ' -- ok \(.+\)'
stdout ''
stdout ' -------------------------'
stdout ' -- .+'
stdout ' -- 1 version with errors'
stdout ' -- 1 schema change'
stdout ' -- 1 diagnostic'
# Expect the command to fail; exit code 1.
! atlas migrate lint --dir file://migrations --dev-url URL --latest=2
stdout 'Analyzing changes from version 1 to 3 \(2 migrations in total\):'
stdout ''
stdout ' -- analyzing version 2'
stdout ' -- destructive changes detected:'
stdout ' -- L1: Dropping table "users" https://atlasgo.io/lint/analyzers#DS102'
stdout ' -- suggested fix:'
stdout ' -> Add a pre-migration check to ensure table "users" is empty before dropping it'
stdout ' -- ok \(.+\)'
stdout ''
stdout ' -- analyzing version 3'
stdout ' -- destructive changes detected:'
stdout ' -- L1: Dropping table "pets" https://atlasgo.io/lint/analyzers#DS102'
stdout ' -- suggested fix:'
stdout ' -> Add a pre-migration check to ensure table "pets" is empty before dropping it'
stdout ' -- ok \(.+\)'
stdout ''
stdout ' -------------------------'
stdout ' -- .+'
stdout ' -- 2 versions with errors'
stdout ' -- 2 schema changes'
stdout ' -- 2 diagnostics'
-- migrations/1.sql --
CREATE TABLE users (id int);
CREATE TABLE pets (id int);
ALTER TABLE users RENAME COLUMN id TO oid;
-- migrations/2.sql --
DROP TABLE users;
-- migrations/3.sql --
DROP TABLE pets;
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-lint-ignore.txtar
================================================
# Ignore all diagnostics.
atlas migrate lint --dir file://migrations1 --dev-url URL --latest=1
stdout 'Analyzing changes from version 1 to 2 \(1 migration in total\):'
stdout ''
stdout ' -- analyzing version 2'
stdout ' -- no diagnostics found'
stdout ' -- ok \(.+\)'
stdout ''
stdout ' -------------------------'
stdout ' -- .+'
stdout ' -- 1 version ok'
stdout ' -- 2 schema changes'
# Ignore specific diagnostics.
atlas migrate lint --dir file://migrations2 --dev-url URL --latest=1
stdout 'Analyzing changes from version 1 to 2 \(1 migration in total\):'
stdout ''
stdout ' -- analyzing version 2'
stdout ' -- no diagnostics found'
stdout ' -- ok \(.+\)'
stdout ''
stdout ' -------------------------'
stdout ' -- .+'
stdout ' -- 1 version ok'
stdout ' -- 2 schema changes'
# Ignore by code.
atlas migrate lint --dir file://migrations3 --dev-url URL --latest=1
stdout 'Analyzing changes from version 1 to 2 \(1 migration in total\):'
stdout ''
stdout ' -- analyzing version 2'
stdout ' -- data dependent changes detected:'
stdout ' -- L1: Adding a non-nullable "text" column "name" will fail in case table "users" is not'
stdout ' empty https://atlasgo.io/lint/analyzers#MF103'
stdout ' -- ok \(.+\)'
stdout ''
stdout ' -------------------------'
stdout ' -- .+'
stdout ' -- 1 version with warnings'
stdout ' -- 2 schema changes'
stdout ' -- 1 diagnostic'
# Ignore entire file.
atlas migrate lint --dir file://migrations4 --dev-url URL --latest=1
stdout ''
# Ignore destructive changes globally.
atlas migrate lint --dir file://migrations5 --dev-url URL --latest=1
stdout 'Analyzing changes from version 1 to 2 \(1 migration in total\):'
stdout ''
stdout ' -- analyzing version 2'
stdout ' -- data dependent changes detected:'
stdout ' -- L4: Adding a non-nullable "text" column "name" will fail in case table "users" is not'
stdout ' empty https://atlasgo.io/lint/analyzers#MF103'
stdout ' -- ok \(.+\)'
stdout ''
stdout ' -------------------------'
stdout ' -- .+'
stdout ' -- 1 version with warnings'
stdout ' -- 2 schema changes'
stdout ' -- 1 diagnostic'
# Ignore multiple change codes globally.
atlas migrate lint --dir file://migrations6 --dev-url URL --latest=1
stdout 'Analyzing changes from version 1 to 2 \(1 migration in total\):'
stdout ''
stdout ' -- analyzing version 2'
stdout ' -- no diagnostics found'
stdout ' -- ok (.+)'
stdout ''
stdout ' -------------------------'
stdout ' -- .+'
stdout ' -- 1 version ok'
stdout ' -- 2 schema changes'
-- migrations1/1.sql --
CREATE TABLE users (id int);
CREATE TABLE pets (id int);
-- migrations1/2.sql --
-- atlas:nolint
ALTER TABLE users ADD COLUMN name text NOT NULL;
-- atlas:nolint
DROP TABLE pets;
-- migrations2/1.sql --
CREATE TABLE users (id int);
CREATE TABLE pets (id int);
-- migrations2/2.sql --
-- atlas:nolint data_depend
ALTER TABLE users ADD COLUMN name text NOT NULL;
-- atlas:nolint destructive
DROP TABLE pets;
-- migrations3/1.sql --
CREATE TABLE users (id int);
CREATE TABLE pets (id int);
-- migrations3/2.sql --
ALTER TABLE users ADD COLUMN name text NOT NULL;
-- atlas:nolint DS102
DROP TABLE pets;
-- migrations4/1.sql --
CREATE TABLE users (id int);
CREATE TABLE pets (id int);
-- migrations4/2.sql --
-- atlas:nolint
DROP TABLE pets;
ALTER TABLE users ADD COLUMN name text NOT NULL;
-- migrations5/1.sql --
CREATE TABLE users (id int);
CREATE TABLE pets (id int);
-- migrations5/2.sql --
-- atlas:nolint destructive
DROP TABLE pets;
ALTER TABLE users ADD COLUMN name text NOT NULL;
-- migrations6/1.sql --
CREATE TABLE users (id int);
CREATE TABLE pets (id int);
-- migrations6/2.sql --
-- atlas:nolint destructive data_depend
DROP TABLE pets;
ALTER TABLE users ADD COLUMN name text NOT NULL;
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-lint-minimal-env.txtar
================================================
# Expect the command to fail; exit code 1.
! atlas migrate lint --env local --latest=2
stdout 'Analyzing changes until version 2 \(2 migrations in total\):'
stdout ''
stdout ' -- analyzing version 1'
stdout ' -- no diagnostics found'
stdout ' -- ok \(.+\)'
stdout ''
stdout ' -- analyzing version 2'
stdout ' -- destructive changes detected:'
stdout ' -- L1: Dropping table "users" https://atlasgo.io/lint/analyzers#DS102'
stdout ' -- suggested fix:'
stdout ' -> Add a pre-migration check to ensure table "users" is empty before dropping it'
stdout ' -- ok \(.+\)'
stdout ''
stdout ' -------------------------'
stdout ' -- .+'
stdout ' -- 1 version ok, 1 with errors'
stdout ' -- 2 schema changes'
stdout ' -- 1 diagnostic'
-- atlas.hcl --
env "local" {
dev = "URL"
}
-- migrations/1.sql --
CREATE TABLE users (id int);
-- migrations/2.sql --
DROP TABLE users;
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-lint-project.txtar
================================================
atlas migrate lint --dir file://migrations --dev-url URL --env=log_name > got.txt
cmp got.txt expected1.txt
atlas migrate lint --dir file://migrations --dev-url URL --env=log_count > got.txt
cmp got.txt expected2.txt
-- migrations/1.sql --
CREATE TABLE users (id int);
CREATE TABLE pets (id int);
ALTER TABLE users RENAME COLUMN id TO oid;
-- migrations/2.sql --
DROP TABLE users;
-- migrations/3.sql --
DROP TABLE pets;
-- expected1.txt --
3.sql
-- expected2.txt --
2
-- atlas.hcl --
lint {
latest = 1
destructive {
error = false
}
}
env "log_name" {
lint {
log = "{{ range .Files }}{{ println .Name }}{{ end }}"
}
}
env "log_count" {
lint {
latest = 2
log = "{{ len .Files | println }}"
}
}
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-project-multifile.txtar
================================================
atlas migrate diff --env local
cmpmig 0 diff.sql
# reset
exec rm -rf migrations
atlas migrate diff --env src_list
cmpmig 0 diff.sql
# reset
exec rm -rf migrations
atlas migrate diff --env single_elem
cmpmig 0 diff.sql
-- atlas.hcl --
env "local" {
url = "URL"
dev = "sqlite://test?mode=memory&_fk=1"
src = "./schema"
migration {
dir = "file://migrations"
format = atlas
}
}
env "src_list" {
url = "URL"
dev = "sqlite://test?mode=memory&_fk=1"
src = [
"./schema/1.hcl",
"./schema/2.hcl",
]
migration {
dir = "file://migrations"
format = atlas
}
}
env "single_elem" {
url = "URL"
dev = "sqlite://test?mode=memory&_fk=1"
src = [
"./schema/",
]
migration {
dir = "file://migrations"
format = atlas
}
}
-- schema/1.hcl --
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
}
-- schema/2.hcl --
schema "main" {
}
-- diff.sql --
-- Create "users" table
CREATE TABLE `users` (`id` int NOT NULL);
-- empty.sql --
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-project.txtar
================================================
exec mkdir migrations
atlas migrate diff --env local
cmpmig 0 diff.sql
atlas migrate validate --env local
atlas migrate new 1 --env local
cmpmig 1 empty.sql
exec touch migrations/2.sql
! atlas migrate validate --env local
stderr 'Error: checksum mismatch'
atlas migrate hash --env local
atlas migrate validate --env local
-- atlas.hcl --
env "local" {
url = "URL"
dev = "sqlite://test?mode=memory&_fk=1"
src = "./1.hcl"
migration {
dir = "file://migrations"
format = atlas
}
}
-- 1.hcl --
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
}
schema "main" {
}
-- diff.sql --
-- Create "users" table
CREATE TABLE `users` (`id` int NOT NULL);
-- empty.sql --
================================================
FILE: internal/integration/testdata/sqlite/cli-migrate-set.txtar
================================================
! atlas migrate set 0
stderr 'Error: checksum file not found'
stdout 'You have a checksum error in your migration directory.'
atlas migrate hash
! atlas migrate set --url URL
stderr 'Error: accepts 1 arg\(s\), received 0'
! atlas migrate set --url URL foo bar
stderr 'Error: accepts 1 arg\(s\), received 2'
# Works on fresh database.
atlas migrate set 1 --url URL
atlas migrate apply 1 --url URL --dry-run
stdout 'Migrating to version 2 from 1'
# Set to second last migration.
atlas migrate set 2 --url URL
atlas migrate apply 1 --url URL --dry-run
stdout 'Migrating to version 3 from 2'
# Have one migration applied, manual do second, set revision and continue apply.
clearSchema
atlas migrate apply 1 --url URL
stdout 'Migrating to version 1'
atlas migrate set 2 --url URL
atlas migrate apply 1 --url URL --dry-run
stdout 'Migrating to version 3 from 2'
# Set to non-existing migration requires flag.
! atlas migrate set 4 --url URL
stderr 'Error: migration with version "4" not found'
# If set to last version, nothing to do.
atlas migrate set 3 --url URL
atlas migrate apply --url URL
stdout 'No migration files to execute'
# Partially applied (error), fix with set.
clearSchema
mv broken.sql migrations/4.sql
atlas migrate hash
! atlas migrate apply --url URL --tx-mode none
stdout 'Migrating to version 4'
atlas migrate set 4 --url URL
atlas migrate apply --url URL
stdout 'No migration files to execute'
-- migrations/1_first.sql --
CREATE TABLE `users` (`id` bigint NOT NULL, `age` bigint NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`));
-- migrations/2_second.sql --
ALTER TABLE `users` ADD UNIQUE INDEX `age` (`age`);
-- migrations/3_third.sql --
CREATE TABLE `pets` (`id` bigint NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`));
-- broken.sql --
CREATE TABLE `vets` (`id` bigint NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY(`id`));
asdf ALTER TABLE `users` ADD UNIQUE INDEX `name` (`name`);
================================================
FILE: internal/integration/testdata/sqlite/cli-project-vars.txtar
================================================
! atlas schema apply --env local --auto-approve
stderr 'Error: missing value for required variable "user_status_default"'
atlas schema apply --env local --auto-approve --var user_status_default=hello
cmpshow users expected.sql
-- atlas.hcl --
variable "user_status_default" {
type = string
}
env "local" {
url = "URL"
src = "./1.hcl"
def_val = var.user_status_default
}
-- 1.hcl --
variable "def_val" {
type = string
}
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
column "status" {
null = true
type = text
default = var.def_val
}
}
schema "main" {
}
-- expected.sql --
CREATE TABLE `users` (
`id` int NOT NULL,
`status` text NULL DEFAULT 'hello'
)
================================================
FILE: internal/integration/testdata/sqlite/cli-schema-project-file.txtar
================================================
! atlas schema inspect
stderr '"url" not set'
! atlas schema apply -f 1.hcl
stderr '"url" not set'
! atlas schema apply --url URL
stderr 'one of flag\(s\) "file" or "to" is required'
! atlas schema apply -f atlas.hcl -u URL
stderr 'cannot parse project file'
# Verify "url" and "src" attributes of the env are used.
atlas schema apply --env local --auto-approve
atlas schema inspect --env local > inspected.hcl
cmp 1.hcl inspected.hcl
# Verify the precedence of flag over project file.
atlas schema apply --env local --auto-approve -f 2.hcl
atlas schema inspect --env local > inspected.hcl
cmp 2.hcl inspected.hcl
-- atlas.hcl --
env "local" {
url = "URL"
src = "./1.hcl"
}
-- 1.hcl --
table "users" {
schema = schema.main
column "id" {
null = false
type = int
}
}
schema "main" {
}
-- 2.hcl --
table "other" {
schema = schema.main
column "id" {
null = false
type = int
}
}
schema "main" {
}
================================================
FILE: internal/integration/testdata/sqlite/column-default.txtar
================================================
execsql 'CREATE TABLE tbl (col)'
cmphcl 1.hcl
-- 1.hcl --
table "tbl" {
schema = schema.main
column "col" {
null = true
type = blob
}
}
schema "main" {
}
================================================
FILE: internal/integration/testdata/sqlite/column-generated.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
# Insert a few records to the table, and check the
# migration process using a temporary table.
execsql 'INSERT INTO users (a) VALUES (1), (2), (3)'
apply 2.hcl
cmpshow users 2.sql
apply 3.hcl
cmpshow users 3.sql
# Appending a new VIRTUAL column should use ALTER command.
apply 4.hcl
cmpshow users 4.sql
-- 1.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "a" {
type = int
}
column "b" {
type = int
as = "1"
}
column "c" {
type = int
as {
expr = "2"
type = STORED
}
}
}
-- 1.sql --
CREATE TABLE `users` (`a` int NOT NULL, `b` int NOT NULL AS (1) VIRTUAL, `c` int NOT NULL AS (2) STORED)
-- 2.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "a" {
type = int
}
column "b" {
type = int
as = "1"
}
column "c" {
type = int
as {
expr = "2"
type = VIRTUAL
}
}
}
-- 2.sql --
CREATE TABLE "users" (`a` int NOT NULL, `b` int NOT NULL AS (1) VIRTUAL, `c` int NOT NULL AS (2) VIRTUAL)
-- 3.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "a" {
type = int
}
column "b" {
type = int
as = "2"
}
column "c" {
type = int
as {
expr = "3"
type = VIRTUAL
}
}
}
-- 3.sql --
CREATE TABLE "users" (`a` int NOT NULL, `b` int NOT NULL AS (2) VIRTUAL, `c` int NOT NULL AS (3) VIRTUAL)
-- 4.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "a" {
type = int
}
column "b" {
type = int
as = "2"
}
column "c" {
type = int
as {
expr = "3"
type = VIRTUAL
}
}
column "d" {
type = int
as {
expr = "4"
type = VIRTUAL
}
}
}
-- 4.sql --
CREATE TABLE "users" (`a` int NOT NULL, `b` int NOT NULL AS (2) VIRTUAL, `c` int NOT NULL AS (3) VIRTUAL, `d` int NOT NULL AS (4) VIRTUAL)
================================================
FILE: internal/integration/testdata/sqlite/column-user-defined.txtar
================================================
# Initial changes.
atlas schema apply --url URL --dev-url DEV_URL --to file://schema.v1.hcl --auto-approve
atlas schema apply --url URL --dev-url DEV_URL --to file://schema.v1.hcl --auto-approve
stdout 'Schema is synced, no changes to be made'
atlas schema inspect --url URL > got
cmp schema.v1.hcl.inspected got
# Changing user defined type.
atlas schema apply --url URL --dev-url DEV_URL --to file://schema.v2.hcl --auto-approve
atlas schema apply --url URL --dev-url DEV_URL --to file://schema.v2.hcl --auto-approve
stdout 'Schema is synced, no changes to be made'
atlas schema inspect --url URL > got
cmp schema.v2.hcl.inspected got
-- schema.v1.hcl --
table "t" {
schema = schema.main
column "c" {
null = true
type = sql("USER_DEFINED")
}
}
schema "main" {
}
-- schema.v1.hcl.inspected --
table "t" {
schema = schema.main
column "c" {
null = true
type = sql("USER_DEFINED")
}
}
schema "main" {
}
-- schema.v2.hcl --
table "t" {
schema = schema.main
column "c" {
null = true
type = sql("USER_TYPE")
}
}
schema "main" {
}
-- schema.v2.hcl.inspected --
table "t" {
schema = schema.main
column "c" {
null = true
type = sql("USER_TYPE")
}
}
schema "main" {
}
================================================
FILE: internal/integration/testdata/sqlite/index-desc.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
# Drop the "DESC" option from the key part.
apply 2.hcl
cmpshow users 2.sql
# Use of "columns" instead of "on" should not trigger a change.
synced 2-no-change.hcl
apply 3.hcl
cmpshow users 3.sql
-- 1.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "rank" {
type = int
}
index "rank_idx" {
on {
desc = true
column = table.users.column.rank
}
}
}
-- 1.sql --
CREATE TABLE `users` (`rank` int NOT NULL)
CREATE INDEX `rank_idx` ON `users` (`rank` DESC)
-- 2.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "rank" {
type = int
}
index "rank_idx" {
on {
column = table.users.column.rank
}
}
}
-- 2.sql --
CREATE TABLE "users" (`rank` int NOT NULL)
CREATE INDEX `rank_idx` ON `users` (`rank`)
-- 2-no-change.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "rank" {
type = int
}
index "rank_idx" {
columns = [
table.users.column.rank,
]
}
}
-- 3.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "rank" {
type = int
}
column "score" {
type = int
}
index "rank_score_idx" {
on {
column = table.users.column.rank
}
on {
column = table.users.column.score
desc = true
}
}
}
-- 3.sql --
CREATE TABLE "users" (`rank` int NOT NULL, `score` int NOT NULL)
CREATE INDEX `rank_score_idx` ON `users` (`rank`, `score` DESC)
================================================
FILE: internal/integration/testdata/sqlite/index-expr.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
apply 2.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "first_name" {
null = false
type = text
}
column "last_name" {
null = false
type = text
}
index "full_name" {
on {
expr = "first_name || ' ' || last_name"
}
}
}
-- 1.sql --
CREATE TABLE `users` (`first_name` text NOT NULL, `last_name` text NOT NULL)
CREATE INDEX `full_name` ON `users` ((first_name || ' ' || last_name))
-- 2.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "first_name" {
null = false
type = text
}
index "full_name" {
on {
expr = "lower(first_name) || '''s first name'"
}
}
}
-- 2.sql --
CREATE TABLE "users" (`first_name` text NOT NULL)
CREATE INDEX `full_name` ON `users` ((lower(first_name) || '''s first name'))
================================================
FILE: internal/integration/testdata/sqlite/index-partial.txtar
================================================
apply 1.hcl
cmpshow users 1.sql
apply 2.hcl
cmpshow users 2.sql
-- 1.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "name" {
null = false
type = text
}
column "active" {
null = true
type = boolean
}
index "users_name" {
columns = [column.name]
where = "active"
}
}
-- 1.sql --
CREATE TABLE `users` (`name` text NOT NULL, `active` boolean NULL)
CREATE INDEX `users_name` ON `users` (`name`) WHERE active
-- 2.hcl --
schema "main" {}
table "users" {
schema = schema.main
column "name" {
null = false
type = text
}
column "active" {
null = true
type = boolean
}
index "users_name" {
columns = [column.name]
where = "active AND name <> ''"
}
}
-- 2.sql --
CREATE TABLE "users" (`name` text NOT NULL, `active` boolean NULL)
CREATE INDEX `users_name` ON `users` (`name`) WHERE active AND name <> ''
================================================
FILE: internal/integration/testdata/sqlite/table-options.txtar
================================================
apply 1.hcl
cmpshow t1 1.sql
cmpshow t2 2.sql
cmpshow t3 3.sql
# Drop options.
apply 2.hcl
cmpshow t1 11.sql
-- 1.hcl --
schema "main" {}
table "t1" {
schema = schema.main
column "id" {
null = false
type = integer
}
primary_key {
columns = [column.id]
}
strict = true
without_rowid = true
}
table "t2" {
schema = schema.main
column "id" {
null = false
type = integer
}
primary_key {
columns = [column.id]
}
strict = true
}
table "t3" {
schema = schema.main
column "id" {
null = false
type = integer
}
primary_key {
columns = [column.id]
}
without_rowid = true
}
-- 1.sql --
CREATE TABLE `t1` (`id` integer NOT NULL, PRIMARY KEY (`id`)) WITHOUT ROWID, STRICT
-- 2.sql --
CREATE TABLE `t2` (`id` integer NOT NULL, PRIMARY KEY (`id`)) STRICT
-- 3.sql --
CREATE TABLE `t3` (`id` integer NOT NULL, PRIMARY KEY (`id`)) WITHOUT ROWID
-- 2.hcl --
schema "main" {}
table "t1" {
schema = schema.main
column "id" {
null = false
type = integer
}
primary_key {
columns = [column.id]
}
}
-- 11.sql --
CREATE TABLE "t1" (`id` integer NOT NULL, PRIMARY KEY (`id`))
================================================
FILE: internal/integration/tidb_test.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package integration
import (
"context"
"database/sql"
"fmt"
"log"
"testing"
"ariga.io/atlas/sql/mysql"
"ariga.io/atlas/sql/schema"
_ "github.com/go-sql-driver/mysql"
"github.com/stretchr/testify/require"
)
var tidbTests = map[string]*myTest{
"tidb5": {port: 4309},
"tidb6": {port: 4310},
}
func tidbRun(t *testing.T, fn func(*myTest)) {
for version, tt := range tidbTests {
if flagVersion == "" || flagVersion == version {
t.Run(version, func(t *testing.T) {
tt.once.Do(func() {
var err error
tt.version = version
tt.rrw = &rrw{}
tt.db, err = sql.Open("mysql", fmt.Sprintf("root@tcp(localhost:%d)/test?parseTime=True", tt.port))
if err != nil {
log.Fatalln(err)
}
dbs = append(dbs, tt.db) // close connection after all tests have been run
tt.drv, err = mysql.Open(tt.db)
if err != nil {
log.Fatalln(err)
}
})
tt := &myTest{T: t, db: tt.db, drv: tt.drv, version: version, port: tt.port, rrw: tt.rrw}
fn(tt)
})
}
}
}
func TestTiDB_AddDropTable(t *testing.T) {
tidbRun(t, func(t *myTest) {
testAddDrop(t)
})
}
func TestTiDB_Relation(t *testing.T) {
tidbRun(t, func(t *myTest) {
testRelation(t)
})
}
func TestTiDB_AddIndexedColumns(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
usersT.Columns = append(usersT.Columns, &schema.Column{
Name: "a",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.RawExpr{X: "10"},
}, &schema.Column{
Name: "b",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.RawExpr{X: "10"},
}, &schema.Column{
Name: "c",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
Default: &schema.RawExpr{X: "10"},
})
parts := usersT.Columns[len(usersT.Columns)-3:]
usersT.Indexes = append(usersT.Indexes, &schema.Index{
Unique: true,
Name: "a_b_c_unique",
Parts: []*schema.IndexPart{{C: parts[0]}, {C: parts[1]}, {C: parts[2]}},
})
changes := t.diff(t.loadUsers(), usersT)
require.NotEmpty(t, changes, "usersT contains 2 new columns and 1 new index")
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// In MySQL, dropping a column should remove it from the key.
// However, on TiDB an explicit DROP/ADD INDEX is required.
idx, ok := usersT.Index("a_b_c_unique")
require.True(t, ok)
idx.Parts = idx.Parts[:len(idx.Parts)-1]
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
changes = t.diff(t.loadUsers(), usersT)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, t.loadUsers())
// Dropping a column from both table and index.
usersT = t.loadUsers()
idx, ok = usersT.Index("a_b_c_unique")
require.True(t, ok)
require.Len(t, idx.Parts, 2)
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
idx.Parts = idx.Parts[:len(idx.Parts)-1]
changes = t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, t.loadUsers())
// Dropping a column should remove
// single-column keys as well.
usersT = t.loadUsers()
idx, ok = usersT.Index("a_b_c_unique")
require.True(t, ok)
require.Len(t, idx.Parts, 1)
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
// In MySQL, dropping a column should remove its index.
// However, on TiDB an explicit DROP INDEX is required.
usersT.Indexes = nil
changes = t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, t.loadUsers())
_, ok = t.loadUsers().Index("a_b_c_unique")
require.False(t, ok)
})
}
func TestTiDB_AddColumns(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := t.users()
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
usersT.Columns = append(
usersT.Columns,
&schema.Column{Name: "a", Type: &schema.ColumnType{Raw: "tinyblob", Type: &schema.BinaryType{T: "tinyblob"}}},
&schema.Column{Name: "b", Type: &schema.ColumnType{Raw: "mediumblob", Type: &schema.BinaryType{T: "mediumblob"}}},
&schema.Column{Name: "c", Type: &schema.ColumnType{Raw: "blob", Type: &schema.BinaryType{T: "blob"}}},
&schema.Column{Name: "d", Type: &schema.ColumnType{Raw: "longblob", Type: &schema.BinaryType{T: "longblob"}}},
&schema.Column{Name: "e", Type: &schema.ColumnType{Raw: "binary", Type: &schema.BinaryType{T: "binary"}}},
&schema.Column{Name: "f", Type: &schema.ColumnType{Raw: "varbinary(255)", Type: &schema.BinaryType{T: "varbinary(255)"}}, Default: &schema.Literal{V: "foo"}},
&schema.Column{Name: "g", Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar", Size: 255}}},
&schema.Column{Name: "h", Type: &schema.ColumnType{Raw: "varchar(255)", Type: &schema.StringType{T: "varchar(255)"}}},
&schema.Column{Name: "i", Type: &schema.ColumnType{Raw: "tinytext", Type: &schema.StringType{T: "tinytext"}}},
&schema.Column{Name: "j", Type: &schema.ColumnType{Raw: "mediumtext", Type: &schema.StringType{T: "mediumtext"}}},
&schema.Column{Name: "k", Type: &schema.ColumnType{Raw: "text", Type: &schema.StringType{T: "text"}}},
&schema.Column{Name: "l", Type: &schema.ColumnType{Raw: "longtext", Type: &schema.StringType{T: "longtext"}}},
&schema.Column{Name: "m", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "decimal", Precision: 10, Scale: 6}}},
&schema.Column{Name: "m1", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "decimal"}}},
&schema.Column{Name: "m2", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "decimal", Precision: 2}}},
&schema.Column{Name: "n", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 10, Scale: 2}}},
&schema.Column{Name: "n1", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric"}}},
&schema.Column{Name: "n2", Type: &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 2}}},
&schema.Column{Name: "o", Type: &schema.ColumnType{Type: &schema.FloatType{T: "float", Precision: 2}}},
&schema.Column{Name: "p", Type: &schema.ColumnType{Type: &schema.FloatType{T: "double", Precision: 14}}},
&schema.Column{Name: "q", Type: &schema.ColumnType{Type: &schema.FloatType{T: "real", Precision: 14}}},
&schema.Column{Name: "r", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}},
&schema.Column{Name: "s", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}}},
&schema.Column{Name: "t", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "smallint"}}},
&schema.Column{Name: "u", Type: &schema.ColumnType{Type: &schema.EnumType{T: "enum", Values: []string{"a", "b", "c"}}}},
&schema.Column{Name: "v", Type: &schema.ColumnType{Type: &schema.StringType{T: "char(36)"}}},
&schema.Column{Name: "x", Type: &schema.ColumnType{Type: &schema.SpatialType{T: "line"}}},
&schema.Column{Name: "z", Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp"}}, Default: &schema.RawExpr{X: "CURRENT_TIMESTAMP"}},
)
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 27)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
}
func TestTiDB_ColumnInt(t *testing.T) {
t.Run("ChangeType", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
for _, typ := range []string{"tinyint", "smallint", "mediumint", "bigint"} {
usersT.Columns[0].Type.Type = &schema.IntegerType{T: typ}
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
}
})
})
t.Run("ChangeDefault", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}}, Default: &schema.RawExpr{X: "1"}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
for _, x := range []string{"2", "'3'", "10.1"} {
usersT.Columns[0].Default.(*schema.RawExpr).X = x
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
}
})
})
}
func TestTiDB_ColumnString(t *testing.T) {
t.Run("ChangeType", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar(20)"}}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
for _, typ := range []string{"varchar(255)", "char(120)", "tinytext", "mediumtext", "longtext"} {
usersT.Columns[0].Type.Type = &schema.StringType{T: typ}
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
}
})
})
t.Run("AddWithDefault", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "a", Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar(255)"}}, Default: &schema.RawExpr{X: "hello"}},
{Name: "b", Type: &schema.ColumnType{Type: &schema.StringType{T: "char(255)"}}, Default: &schema.RawExpr{X: "'world'"}},
},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
})
})
t.Run("ChangeDefault", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{{Name: "a", Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar(255)"}}, Default: &schema.RawExpr{X: "hello"}}},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
for _, x := range []string{"2", "'3'", "'world'"} {
usersT.Columns[0].Default.(*schema.RawExpr).X = x
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
}
})
})
}
func TestTiDB_ColumnBool(t *testing.T) {
t.Run("Add", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "a", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}},
{Name: "b", Type: &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}}},
{Name: "c", Type: &schema.ColumnType{Type: &schema.BoolType{T: "tinyint"}}},
{Name: "d", Type: &schema.ColumnType{Type: &schema.BoolType{T: "tinyint(1)"}}},
},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
})
})
t.Run("AddWithDefault", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "a", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "1"}},
{Name: "b", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "0"}},
{Name: "c", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "'1'"}},
{Name: "d", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "'0'"}},
{Name: "e", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "true"}},
{Name: "f", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "false"}},
{Name: "g", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "TRUE"}},
{Name: "h", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "FALSE"}},
},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
})
})
t.Run("ChangeDefault", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "a", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}}, Default: &schema.RawExpr{X: "1"}},
},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
// Change default from "true" to "false" to "true".
for _, x := range []string{"false", "true"} {
usersT.Columns[0].Default.(*schema.RawExpr).X = x
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
}
})
})
t.Run("ChangeNull", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := &schema.Table{
Name: "users",
Columns: []*schema.Column{
{Name: "a", Type: &schema.ColumnType{Type: &schema.BoolType{T: "bool"}, Null: true}},
},
}
t.migrate(&schema.AddTable{T: usersT})
t.dropTables(usersT.Name)
ensureNoChange(t, usersT)
usersT.Columns[0].Type.Null = false
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 1)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
})
}
func TestTiDB_ForeignKey(t *testing.T) {
t.Run("ChangeAction", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT, postsT := t.users(), t.posts()
t.dropTables(postsT.Name, usersT.Name)
t.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})
ensureNoChange(t, postsT, usersT)
postsT = t.loadPosts()
fk, ok := postsT.ForeignKey("author_id")
require.True(t, ok)
fk.OnUpdate = schema.SetNull
fk.OnDelete = schema.Cascade
changes := t.diff(t.loadPosts(), postsT)
require.Len(t, changes, 1)
modifyF, ok := changes[0].(*schema.ModifyForeignKey)
require.True(t, ok)
require.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)
t.migrate(&schema.ModifyTable{T: postsT, Changes: changes})
ensureNoChange(t, postsT, usersT)
})
})
t.Run("UnsetNull", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT, postsT := t.users(), t.posts()
t.dropTables(postsT.Name, usersT.Name)
fk, ok := postsT.ForeignKey("author_id")
require.True(t, ok)
fk.OnDelete = schema.SetNull
fk.OnUpdate = schema.SetNull
t.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})
ensureNoChange(t, postsT, usersT)
postsT = t.loadPosts()
c, ok := postsT.Column("author_id")
require.True(t, ok)
c.Type.Null = false
fk, ok = postsT.ForeignKey("author_id")
require.True(t, ok)
fk.OnUpdate = schema.NoAction
fk.OnDelete = schema.NoAction
changes := t.diff(t.loadPosts(), postsT)
require.Len(t, changes, 2)
modifyC, ok := changes[0].(*schema.ModifyColumn)
require.True(t, ok)
require.True(t, modifyC.Change == schema.ChangeNull)
modifyF, ok := changes[1].(*schema.ModifyForeignKey)
require.True(t, ok)
require.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)
t.migrate(&schema.ModifyTable{T: postsT, Changes: changes})
ensureNoChange(t, postsT, usersT)
})
})
t.Run("AddDrop", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
usersT := t.users()
t.dropTables(usersT.Name)
t.migrate(&schema.AddTable{T: usersT})
ensureNoChange(t, usersT)
// Add foreign key.
usersT.Columns = append(usersT.Columns, &schema.Column{
Name: "spouse_id",
Type: &schema.ColumnType{Raw: "bigint", Type: &schema.IntegerType{T: "bigint"}, Null: true},
})
usersT.ForeignKeys = append(usersT.ForeignKeys, &schema.ForeignKey{
Symbol: "spouse_id",
Table: usersT,
Columns: usersT.Columns[len(usersT.Columns)-1:],
RefTable: usersT,
RefColumns: usersT.Columns[:1],
OnDelete: schema.NoAction,
})
changes := t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
addC, ok := changes[0].(*schema.AddColumn)
require.True(t, ok)
require.Equal(t, "spouse_id", addC.C.Name)
addF, ok := changes[1].(*schema.AddForeignKey)
require.True(t, ok)
require.Equal(t, "spouse_id", addF.F.Symbol)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
// Drop foreign keys.
usersT.Columns = usersT.Columns[:len(usersT.Columns)-1]
usersT.ForeignKeys = usersT.ForeignKeys[:len(usersT.ForeignKeys)-1]
changes = t.diff(t.loadUsers(), usersT)
require.Len(t, changes, 2)
t.migrate(&schema.ModifyTable{T: usersT, Changes: changes})
ensureNoChange(t, usersT)
})
})
}
func TestTiDB_HCL_Realm(t *testing.T) {
tidbRun(t, func(t *myTest) {
t.dropSchemas("second")
realm := t.loadRealm()
hcl, err := mysql.MarshalHCL(realm)
require.NoError(t, err)
wa := string(hcl) + `
schema "second" {
}
`
t.applyRealmHcl(wa)
realm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{
Mode: schema.InspectSchemas | schema.InspectTables,
})
require.NoError(t, err)
_, ok := realm.Schema("test")
require.True(t, ok)
_, ok = realm.Schema("second")
require.True(t, ok)
})
}
func TestTiDB_DefaultsHCL(t *testing.T) {
n := "atlas_defaults"
tidbRun(t, func(t *myTest) {
ddl := `
create table atlas_defaults
(
string varchar(255) default "hello_world",
quoted varchar(100) default 'never say "never"',
tBit bit(10) default b'10101',
ts timestamp default CURRENT_TIMESTAMP,
number int default 42
)
`
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
spec, err := mysql.MarshalHCL(realm.Schemas[0])
require.NoError(t, err)
var s schema.Realm
err = mysql.EvalHCLBytes(spec, &s, nil)
require.NoError(t, err)
t.dropTables(n)
t.applyHcl(string(spec))
ensureNoChange(t, realm.Schemas[0].Tables[0])
})
}
func TestTiDB_CLI_MultiSchema(t *testing.T) {
h := `
schema "test" {
charset = "%s"
collation = "%s"
}
table "users" {
schema = schema.test
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
schema "test2" {
charset = "%s"
collation = "%s"
}
table "users" {
schema = schema.test2
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}`
t.Run("SchemaInspect", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
t.dropSchemas("test2")
t.dropTables("users")
attrs := t.defaultAttrs()
charset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)
testCLIMultiSchemaInspect(t, fmt.Sprintf(h, charset.V, collate.V, charset.V, collate.V), t.url(""), []string{"test", "test2"}, mysql.EvalHCL)
})
})
t.Run("SchemaApply", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
t.dropSchemas("test2")
t.dropTables("users")
attrs := t.defaultAttrs()
charset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)
testCLIMultiSchemaApply(t, fmt.Sprintf(h, charset.V, collate.V, charset.V, collate.V), t.url(""), []string{"test", "test2"}, mysql.EvalHCL)
})
})
}
func TestTiDB_CLI(t *testing.T) {
h := `
schema "test" {
charset = "%s"
collation = "%s"
}
table "users" {
schema = schema.test
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}`
t.Run("SchemaInspect", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
attrs := t.defaultAttrs()
charset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)
testCLISchemaInspect(t, fmt.Sprintf(h, charset.V, collate.V), t.url("test"), mysql.EvalHCL)
})
})
t.Run("SchemaApply", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
attrs := t.defaultAttrs()
charset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)
testCLISchemaApply(t, fmt.Sprintf(h, charset.V, collate.V), t.url("test"))
})
})
t.Run("SchemaApplyWithVars", func(t *testing.T) {
h := `
variable "tenant" {
type = string
}
schema "tenant" {
name = var.tenant
}
table "users" {
schema = schema.tenant
column "id" {
type = int
}
}
`
tidbRun(t, func(t *myTest) {
testCLISchemaApply(t, h, t.url("test"), "--var", "tenant=test")
})
})
t.Run("SchemaApplyDryRun", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
attrs := t.defaultAttrs()
charset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)
testCLISchemaApplyDry(t, fmt.Sprintf(h, charset.V, collate.V), t.url("test"))
})
})
t.Run("SchemaDiffRun", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
testCLISchemaDiff(t, t.url("test"))
})
})
}
func TestTiDB_HCL(t *testing.T) {
full := `
schema "test" {
}
table "users" {
schema = schema.test
column "id" {
type = int
}
primary_key {
columns = [table.users.column.id]
}
}
table "posts" {
schema = schema.test
column "id" {
type = int
}
column "author_id" {
type = int
}
foreign_key "author" {
columns = [
table.posts.column.author_id,
]
ref_columns = [
table.users.column.id,
]
}
primary_key {
columns = [table.users.column.id]
}
}
`
empty := `
schema "test" {
}
`
tidbRun(t, func(t *myTest) {
testHCLIntegration(t, full, empty)
})
}
func TestTiDB_Sanity(t *testing.T) {
n := "atlas_types_sanity"
t.Run("Common", func(t *testing.T) {
ddl := `
create table atlas_types_sanity
(
tBit bit(10) default b'1000000001' null,
tInt int(10) default 4 not null,
tTinyInt tinyint(10) default 8 null,
tSmallInt smallint(10) default 2 null,
tMediumInt mediumint(10) default 11 null,
tBigInt bigint(10) default 4 null,
tDecimal decimal default 4 null,
tNumeric numeric default 4 not null,
tFloat float default 4 null,
tDouble double(10, 0) default 4 null,
tReal double(10, 0) default 4 null,
tTimestamp timestamp default CURRENT_TIMESTAMP null,
tTimestampFraction timestamp(6) default CURRENT_TIMESTAMP(6) null,
tTimestampOnUpdate timestamp default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP null,
tTimestampFractionOnUpdate timestamp(6) default CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) null,
tDate date null,
tTime time null,
tDateTime datetime null,
tYear year null,
tVarchar varchar(10) default 'Titan' null,
tChar char(25) default 'Olimpia' not null,
tVarBinary varbinary(30) default 'Titan' null,
tBinary binary(5) default 'Titan' null,
tBlob blob(5) default null,
tTinyBlob tinyblob null,
tMediumBlob mediumblob default null,
tLongBlob longblob default null,
tText text(13) default null,
tTinyText tinytext default null,
tMediumText mediumtext default null,
tLongText longtext default null,
tEnum enum('a','b') default null,
tSet set('a','b') default null
) CHARSET = latin1;
`
tidbRun(t, func(t *myTest) {
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
require.Len(t, realm.Schemas, 1)
ts, ok := realm.Schemas[0].Table(n)
require.True(t, ok)
expected := schema.Table{
Name: n,
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_bin"},
&mysql.Engine{V: "InnoDB", Default: true},
},
Schema: realm.Schemas[0],
Columns: []*schema.Column{
{
Name: "tBit",
Type: &schema.ColumnType{Type: &mysql.BitType{T: "bit", Size: 10}, Raw: "bit(10) unsigned", Null: true},
Default: &schema.Literal{V: "b'1000000001'"},
},
{
Name: "tInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int", Unsigned: false},
Raw: t.valueByVersion(map[string]string{"mysql8": "int"}, "int(10)"), Null: false},
Default: &schema.Literal{V: "4"},
},
{
Name: "tTinyInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "tinyint", Unsigned: false},
Raw: t.valueByVersion(map[string]string{"mysql8": "tinyint"}, "tinyint(10)"), Null: true},
Default: &schema.Literal{V: "8"},
},
{
Name: "tSmallInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "smallint", Unsigned: false},
Raw: t.valueByVersion(map[string]string{"mysql8": "smallint"}, "smallint(10)"), Null: true},
Default: &schema.Literal{V: "2"},
},
{
Name: "tMediumInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "mediumint", Unsigned: false},
Raw: t.valueByVersion(map[string]string{"mysql8": "mediumint"}, "mediumint(10)"), Null: true},
Default: &schema.Literal{V: "11"},
},
{
Name: "tBigInt",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false},
Raw: t.valueByVersion(map[string]string{"mysql8": "bigint"}, "bigint(10)"), Null: true},
Default: &schema.Literal{V: "4"},
},
{
Name: "tDecimal",
Type: &schema.ColumnType{Type: &schema.DecimalType{T: "decimal", Precision: 10},
Raw: "decimal(10,0)", Null: true},
Default: &schema.Literal{V: "4"},
},
{
Name: "tNumeric",
Type: &schema.ColumnType{Type: &schema.DecimalType{T: "decimal", Precision: 10},
Raw: "decimal(10,0)", Null: false},
Default: &schema.Literal{V: "4"},
},
{
Name: "tFloat",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "float"},
Raw: "float", Null: true},
Default: &schema.Literal{V: "4"},
},
{
Name: "tDouble",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "double"},
Raw: "double", Null: true},
Default: &schema.Literal{V: "4"},
},
{
Name: "tReal",
Type: &schema.ColumnType{Type: &schema.FloatType{T: "double"},
Raw: "double", Null: true},
Default: &schema.Literal{V: "4"},
},
{
Name: "tTimestamp",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp"},
Raw: "timestamp", Null: true},
Default: &schema.RawExpr{
X: "CURRENT_TIMESTAMP",
},
},
{
Name: "tTimestampFraction",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp", Precision: intp(6)},
Raw: "timestamp(6)", Null: true},
Default: &schema.RawExpr{
X: "CURRENT_TIMESTAMP(6)",
},
},
{
Name: "tTimestampOnUpdate",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp"},
Raw: "timestamp", Null: true},
Default: &schema.RawExpr{
X: "CURRENT_TIMESTAMP",
},
Attrs: []schema.Attr{
&mysql.OnUpdate{
A: "CURRENT_TIMESTAMP",
},
},
},
{
Name: "tTimestampFractionOnUpdate",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "timestamp", Precision: intp(6)},
Raw: "timestamp(6)", Null: true},
Default: &schema.RawExpr{
X: "CURRENT_TIMESTAMP(6)",
},
Attrs: []schema.Attr{
&mysql.OnUpdate{
A: "CURRENT_TIMESTAMP(6)",
},
},
},
{
Name: "tDate",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "date"},
Raw: "date", Null: true},
},
{
Name: "tTime",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "time"},
Raw: "time", Null: true},
},
{
Name: "tDateTime",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "datetime"},
Raw: "datetime", Null: true},
},
{
Name: "tYear",
Type: &schema.ColumnType{Type: &schema.TimeType{T: "year", Precision: intp(t.intByVersion(map[string]int{"mysql8": 0}, 4))},
Raw: t.valueByVersion(map[string]string{"mysql8": "year"}, "year(4) unsigned"), Null: true},
},
{
Name: "tVarchar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar", Size: 10},
Raw: "varchar(10)", Null: true},
Default: &schema.Literal{V: t.quoted("Titan")},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_bin"},
},
},
{
Name: "tChar",
Type: &schema.ColumnType{Type: &schema.StringType{T: "char", Size: 25},
Raw: "char(25)", Null: false},
Default: &schema.Literal{V: t.quoted("Olimpia")},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_bin"},
},
},
{
Name: "tVarBinary",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "varbinary", Size: intp(30)},
Raw: "varbinary(30)", Null: true},
Default: &schema.Literal{V: t.valueByVersion(map[string]string{"mysql8": "0x546974616E"}, t.quoted("Titan"))},
},
{
Name: "tBinary",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "binary", Size: intp(5)},
Raw: "binary(5)", Null: true},
Default: &schema.Literal{V: t.valueByVersion(map[string]string{"mysql8": "0x546974616E"}, t.quoted("Titan"))},
},
{
Name: "tBlob",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "tinyblob"},
Raw: "tinyblob", Null: true},
},
{
Name: "tTinyBlob",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "tinyblob"},
Raw: "tinyblob", Null: true},
},
{
Name: "tMediumBlob",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "mediumblob"},
Raw: "mediumblob", Null: true},
},
{
Name: "tLongBlob",
Type: &schema.ColumnType{Type: &schema.BinaryType{T: "longblob"},
Raw: "longblob", Null: true},
},
{
Name: "tText",
Type: &schema.ColumnType{Type: &schema.StringType{T: "tinytext"},
Raw: "tinytext", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_bin"},
},
},
{
Name: "tTinyText",
Type: &schema.ColumnType{Type: &schema.StringType{T: "tinytext"},
Raw: "tinytext", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_bin"},
},
},
{
Name: "tMediumText",
Type: &schema.ColumnType{Type: &schema.StringType{T: "mediumtext", Size: 0},
Raw: "mediumtext", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_bin"},
},
},
{
Name: "tLongText",
Type: &schema.ColumnType{Type: &schema.StringType{T: "longtext", Size: 0},
Raw: "longtext", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_bin"},
},
},
{
Name: "tEnum",
Type: &schema.ColumnType{Type: &schema.EnumType{T: "enum", Values: []string{"a", "b"}},
Raw: "enum('a','b')", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_bin"},
},
},
{
Name: "tSet",
Type: &schema.ColumnType{Type: &mysql.SetType{Values: []string{"a", "b"}},
Raw: "set('a','b')", Null: true},
Attrs: []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_bin"},
},
},
},
}
rmCreateStmt(ts)
require.EqualValues(t, &expected, ts)
t.hclDriftTest(n, realm, expected)
})
})
t.Run("JSON", func(t *testing.T) {
ddl := `
create table atlas_types_sanity
(
tJSON json default null
) CHARSET = latin1;
`
tidbRun(t, func(t *myTest) {
t.dropTables(n)
_, err := t.db.Exec(ddl)
require.NoError(t, err)
realm := t.loadRealm()
require.Len(t, realm.Schemas, 1)
ts, ok := realm.Schemas[0].Table(n)
require.True(t, ok)
expected := schema.Table{
Name: n,
Attrs: func() []schema.Attr {
return []schema.Attr{
&schema.Charset{V: "latin1"},
&schema.Collation{V: "latin1_bin"},
&mysql.Engine{V: "InnoDB", Default: true},
}
}(),
Schema: realm.Schemas[0],
Columns: []*schema.Column{
{Name: "tJSON", Type: &schema.ColumnType{Type: &schema.JSONType{T: "json"}, Raw: "json", Null: true}},
},
}
rmCreateStmt(ts)
require.EqualValues(t, &expected, ts)
})
})
t.Run("ImplicitIndexes", func(t *testing.T) {
tidbRun(t, func(t *myTest) {
testImplicitIndexes(t, t.db)
})
})
t.Run("AltersOrder", func(t *testing.T) {
ddl := `
create table tidb_alter_order(
tBigInt bigint(10) default 4 null,
INDEX i (tBigInt)
);
`
tidbRun(t, func(t *myTest) {
t.dropTables("tidb_alter_order")
_, err := t.db.Exec(ddl)
require.NoError(t, err)
tbl := t.loadTable("tidb_alter_order")
require.NotNil(t, tbl)
to := schema.Table{
Name: "tidb_alter_order",
Attrs: func() []schema.Attr {
return []schema.Attr{
&schema.Collation{V: "utf8mb4_bin"},
&schema.Charset{V: "utf8mb4"},
&mysql.Engine{V: "InnoDB", Default: true},
}
}(),
Columns: []*schema.Column{
{
Name: "tBigInt2",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false},
Raw: t.valueByVersion(map[string]string{"mysql8": "bigint"}, "bigint(10)"), Null: true},
Default: &schema.Literal{V: "4"},
},
},
}
to.AddIndexes(
&schema.Index{Name: "i2", Parts: []*schema.IndexPart{
{
C: to.Columns[0],
Desc: true,
},
}})
changes, err := t.drv.SchemaDiff(schema.New("test").AddTables(tbl), schema.New("test").AddTables(&to))
require.NoError(t, err)
err = t.drv.ApplyChanges(context.Background(), changes)
require.NoError(t, err)
t.migrate()
rmCreateStmt(tbl)
})
})
}
================================================
FILE: internal/integration/tools.go
================================================
//go:build tools
// +build tools
package main
import (
_ "ariga.io/atlas/cmd/atlas"
)
================================================
FILE: schemahcl/context.go
================================================
// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package schemahcl
import (
"context"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
)
// blockVar is an HCL resource that defines an input variable to the Atlas DDL document.
type blockVar struct {
Name string `hcl:",label"`
Type cty.Value `hcl:"type"`
Default cty.Value `hcl:"default,optional"`
Description string `hcl:"description,optional"`
}
// setInputVals sets the input values into the evaluation context. HCL documents can define
// input variables in the document body by defining "variable" blocks:
//
// variable "name" {
// type = string // also supported: number, bool
// default = "rotemtam"
// }
func (s *State) setInputVals(ctx *hcl.EvalContext, body hcl.Body, input map[string]cty.Value) error {
var doc struct {
Vars []*blockVar `hcl:"variable,block"`
Remain hcl.Body `hcl:",remain"`
}
if diag := gohcl.DecodeBody(body, ctx, &doc); diag.HasErrors() {
return diag
}
ctxVars := make(map[string]cty.Value)
for _, v := range doc.Vars {
var vv cty.Value
switch iv, ok := input[v.Name]; {
case !v.Type.Type().IsCapsuleType():
return fmt.Errorf(
"invalid type %q for variable %q. Valid types are: string, number, bool, list, map, or set",
v.Type.AsString(), v.Name,
)
case ok:
vv = iv
case v.Default != cty.NilVal:
vv = v.Default
default:
return fmt.Errorf("missing value for required variable %q", v.Name)
}
vt := v.Type.EncapsulatedValue().(*cty.Type)
// In case the input value is a primitive type and the expected type is a list,
// wrap it as a list because the variable type may not be known to the caller.
if vt.IsListType() && vv.Type().Equals(vt.ElementType()) {
vv = cty.ListVal([]cty.Value{vv})
}
cv, err := convert.Convert(vv, *vt)
if err != nil {
return fmt.Errorf("variable %q: %w", v.Name, err)
}
ctxVars[v.Name] = cv
}
mergeCtxVar(ctx, ctxVars)
return nil
}
// evalReferences evaluates local and data blocks.
func (s *State) evalReferences(ctx *hcl.EvalContext, body *hclsyntax.Body) error {
type node struct {
addr [3]string
edges func() []hcl.Traversal
value func() (cty.Value, error)
}
var (
initblk []*node
goctx = s.config.ctx
typeblk = make(map[string]bool)
nodes = make(map[[3]string]*node)
blocks = make(hclsyntax.Blocks, 0, len(body.Blocks))
)
if goctx == nil {
goctx = context.Background()
}
for _, b := range body.Blocks {
switch b := b; {
case b.Type == BlockData:
if len(b.Labels) < 2 {
return fmt.Errorf("data block %q must have exactly 2 labels", b.Type)
}
h, ok := s.config.datasrc[b.Labels[0]]
if !ok {
return fmt.Errorf("missing data source handler for %q", b.Labels[0])
}
// Data references are combined from
// "data", "source" and "name" labels.
addr := [3]string{RefData, b.Labels[0], b.Labels[1]}
nodes[addr] = &node{
addr: addr,
value: func() (cty.Value, error) { return h(goctx, ctx, b) },
edges: func() []hcl.Traversal { return bodyVars(b.Body) },
}
case b.Type == BlockLocals:
for k, v := range b.Body.Attributes {
k, v := k, v
// Local references are combined from
// "local" and "name" labels.
addr := [3]string{RefLocal, k, ""}
nodes[addr] = &node{
addr: addr,
edges: func() []hcl.Traversal { return hclsyntax.Variables(v.Expr) },
value: func() (cty.Value, error) {
v, diags := v.Expr.Value(ctx)
if diags.HasErrors() {
return cty.NilVal, diags
}
return v, nil
},
}
}
case s.config.initblk[b.Type] != nil:
if len(b.Labels) != 0 {
return fmt.Errorf("init block %q cannot have labels", b.Type)
}
addr := [3]string{b.Type, "", ""}
if nodes[addr] != nil {
return fmt.Errorf("duplicate init block %q", b.Type)
}
h := s.config.initblk[b.Type]
n := &node{
addr: addr,
value: func() (cty.Value, error) { return h(goctx, ctx, b) },
edges: func() []hcl.Traversal { return bodyVars(b.Body) },
}
nodes[addr] = n
initblk = append(initblk, n)
case s.config.typedblk[b.Type] != nil:
typeblk[b.Type] = true
if len(b.Labels) < 2 {
return fmt.Errorf("%s block must have exactly 2 labels", b.Type)
}
k, ok := s.config.typedblk[b.Type]
if !ok || k[b.Labels[0]] == nil {
return fmt.Errorf("missing %s block handler for %q", b.Type, b.Labels[0])
}
h := k[b.Labels[0]]
// Typed block references are combined from
// "", "